/**
 * 리포트 관리 서비스
 */

import { v4 as uuidv4 } from "uuid";
import { query, queryOne, transaction } from "../database/db";
import {
  ReportMaster,
  ReportLayout,
  ReportQuery,
  ReportTemplate,
  ReportDetail,
  GetReportsParams,
  GetReportsResponse,
  CreateReportRequest,
  UpdateReportRequest,
  SaveLayoutRequest,
  GetTemplatesResponse,
  CreateTemplateRequest,
} from "../types/report";
import { DatabaseConnectorFactory } from "../database/DatabaseConnectorFactory";
import { ExternalDbConnectionService } from "./externalDbConnectionService";

export class ReportService {
  /**
   * SQL 쿼리 검증 (SELECT만 허용)
   */
  private validateQuerySafety(sql: string): void {
    // 위험한 SQL 명령어 목록
    const dangerousKeywords = [
      "DELETE",
      "DROP",
      "TRUNCATE",
      "INSERT",
      "UPDATE",
      "ALTER",
      "CREATE",
      "REPLACE",
      "MERGE",
      "GRANT",
      "REVOKE",
      "EXECUTE",
      "EXEC",
      "CALL",
    ];

    // SQL을 대문자로 변환하여 검사
    const upperSql = sql.toUpperCase().trim();

    // 위험한 키워드 검사
    for (const keyword of dangerousKeywords) {
      // 단어 경계를 고려하여 검사 (예: DELETE, DELETE FROM 등)
      const regex = new RegExp(`\\b${keyword}\\b`, "i");
      if (regex.test(upperSql)) {
        throw new Error(
          `보안상의 이유로 ${keyword} 명령어는 사용할 수 없습니다. SELECT 쿼리만 허용됩니다.`
        );
      }
    }

    // SELECT 쿼리인지 확인
    if (!upperSql.startsWith("SELECT") && !upperSql.startsWith("WITH")) {
      throw new Error(
        "SELECT 쿼리만 허용됩니다. 데이터 조회 용도로만 사용할 수 있습니다."
      );
    }

    // 세미콜론으로 구분된 여러 쿼리 방지
    const semicolonCount = (sql.match(/;/g) || []).length;
    if (
      semicolonCount > 1 ||
      (semicolonCount === 1 && !sql.trim().endsWith(";"))
    ) {
      throw new Error(
        "보안상의 이유로 여러 개의 쿼리를 동시에 실행할 수 없습니다."
      );
    }
  }

  /**
   * 리포트 목록 조회
   */
  async getReports(params: GetReportsParams): Promise<GetReportsResponse> {
    const {
      page = 1,
      limit = 20,
      searchText = "",
      reportType = "",
      useYn = "Y",
      sortBy = "created_at",
      sortOrder = "DESC",
    } = params;

    const offset = (page - 1) * limit;

    // WHERE 조건 동적 생성
    const conditions: string[] = [];
    const values: any[] = [];
    let paramIndex = 1;

    if (useYn) {
      conditions.push(`use_yn = $${paramIndex++}`);
      values.push(useYn);
    }

    if (searchText) {
      conditions.push(
        `(report_name_kor LIKE $${paramIndex} OR report_name_eng LIKE $${paramIndex})`
      );
      values.push(`%${searchText}%`);
      paramIndex++;
    }

    if (reportType) {
      conditions.push(`report_type = $${paramIndex++}`);
      values.push(reportType);
    }

    const whereClause =
      conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";

    // 전체 개수 조회
    const countQuery = `
      SELECT COUNT(*) as total
      FROM report_master
      ${whereClause}
    `;
    const countResult = await queryOne<{ total: string }>(countQuery, values);
    const total = parseInt(countResult?.total || "0", 10);

    // 목록 조회
    const listQuery = `
      SELECT 
        report_id,
        report_name_kor,
        report_name_eng,
        template_id,
        report_type,
        company_code,
        description,
        use_yn,
        created_at,
        created_by,
        updated_at,
        updated_by
      FROM report_master
      ${whereClause}
      ORDER BY ${sortBy} ${sortOrder}
      LIMIT $${paramIndex++} OFFSET $${paramIndex}
    `;

    const items = await query<ReportMaster>(listQuery, [
      ...values,
      limit,
      offset,
    ]);

    return {
      items,
      total,
      page,
      limit,
    };
  }

  /**
   * 리포트 상세 조회
   */
  async getReportById(reportId: string): Promise<ReportDetail | null> {
    // 리포트 마스터 조회
    const reportQuery = `
      SELECT 
        report_id,
        report_name_kor,
        report_name_eng,
        template_id,
        report_type,
        company_code,
        description,
        use_yn,
        created_at,
        created_by,
        updated_at,
        updated_by
      FROM report_master
      WHERE report_id = $1
    `;
    const report = await queryOne<ReportMaster>(reportQuery, [reportId]);

    if (!report) {
      return null;
    }

    // 레이아웃 조회
    const layoutQuery = `
      SELECT 
        layout_id,
        report_id,
        canvas_width,
        canvas_height,
        page_orientation,
        margin_top,
        margin_bottom,
        margin_left,
        margin_right,
        components,
        created_at,
        created_by,
        updated_at,
        updated_by
      FROM report_layout
      WHERE report_id = $1
    `;
    const layout = await queryOne<ReportLayout>(layoutQuery, [reportId]);

    // 쿼리 조회
    const queriesQuery = `
      SELECT 
        query_id,
        report_id,
        query_name,
        query_type,
        sql_query,
        parameters,
        external_connection_id,
        display_order,
        created_at,
        created_by,
        updated_at,
        updated_by
      FROM report_query
      WHERE report_id = $1
      ORDER BY display_order, created_at
    `;
    const queries = await query<ReportQuery>(queriesQuery, [reportId]);

    // 메뉴 매핑 조회
    const menuMappingQuery = `
      SELECT menu_objid
      FROM report_menu_mapping
      WHERE report_id = $1
      ORDER BY created_at
    `;
    const menuMappings = await query<{ menu_objid: number }>(menuMappingQuery, [
      reportId,
    ]);
    const menuObjids = menuMappings?.map((m) => Number(m.menu_objid)) || [];

    return {
      report,
      layout,
      queries: queries || [],
      menuObjids,
    };
  }

  /**
   * 리포트 생성
   */
  async createReport(
    data: CreateReportRequest,
    userId: string
  ): Promise<string> {
    const reportId = `RPT_${uuidv4().replace(/-/g, "").substring(0, 20)}`;

    return transaction(async (client) => {
      // 리포트 마스터 생성
      const insertReportQuery = `
        INSERT INTO report_master (
          report_id,
          report_name_kor,
          report_name_eng,
          template_id,
          report_type,
          company_code,
          description,
          use_yn,
          created_by
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, 'Y', $8)
      `;

      await client.query(insertReportQuery, [
        reportId,
        data.reportNameKor,
        data.reportNameEng || null,
        data.templateId || null,
        data.reportType,
        data.companyCode || null,
        data.description || null,
        userId,
      ]);

      // 템플릿이 있으면 해당 템플릿의 레이아웃 복사
      if (data.templateId) {
        const templateQuery = `
          SELECT layout_config FROM report_template WHERE template_id = $1
        `;
        const template = await client.query(templateQuery, [data.templateId]);

        if (template.rows.length > 0 && template.rows[0].layout_config) {
          const layoutConfig = JSON.parse(template.rows[0].layout_config);
          const layoutId = `LAY_${uuidv4().replace(/-/g, "").substring(0, 20)}`;

          const insertLayoutQuery = `
            INSERT INTO report_layout (
              layout_id,
              report_id,
              canvas_width,
              canvas_height,
              page_orientation,
              margin_top,
              margin_bottom,
              margin_left,
              margin_right,
              components,
              created_by
            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
          `;

          await client.query(insertLayoutQuery, [
            layoutId,
            reportId,
            layoutConfig.width || 210,
            layoutConfig.height || 297,
            layoutConfig.orientation || "portrait",
            20,
            20,
            20,
            20,
            JSON.stringify([]),
            userId,
          ]);
        }
      }

      return reportId;
    });
  }

  /**
   * 리포트 수정
   */
  async updateReport(
    reportId: string,
    data: UpdateReportRequest,
    userId: string
  ): Promise<boolean> {
    const setClauses: string[] = [];
    const values: any[] = [];
    let paramIndex = 1;

    if (data.reportNameKor !== undefined) {
      setClauses.push(`report_name_kor = $${paramIndex++}`);
      values.push(data.reportNameKor);
    }

    if (data.reportNameEng !== undefined) {
      setClauses.push(`report_name_eng = $${paramIndex++}`);
      values.push(data.reportNameEng);
    }

    if (data.reportType !== undefined) {
      setClauses.push(`report_type = $${paramIndex++}`);
      values.push(data.reportType);
    }

    if (data.description !== undefined) {
      setClauses.push(`description = $${paramIndex++}`);
      values.push(data.description);
    }

    if (data.useYn !== undefined) {
      setClauses.push(`use_yn = $${paramIndex++}`);
      values.push(data.useYn);
    }

    if (setClauses.length === 0) {
      return false;
    }

    setClauses.push(`updated_at = CURRENT_TIMESTAMP`);
    setClauses.push(`updated_by = $${paramIndex++}`);
    values.push(userId);

    values.push(reportId);

    const updateQuery = `
      UPDATE report_master
      SET ${setClauses.join(", ")}
      WHERE report_id = $${paramIndex}
    `;

    const result = await query(updateQuery, values);
    return true;
  }

  /**
   * 리포트 삭제
   */
  async deleteReport(reportId: string): Promise<boolean> {
    return transaction(async (client) => {
      // 쿼리 삭제 (CASCADE로 자동 삭제되지만 명시적으로)
      await client.query(`DELETE FROM report_query WHERE report_id = $1`, [
        reportId,
      ]);

      // 레이아웃 삭제
      await client.query(`DELETE FROM report_layout WHERE report_id = $1`, [
        reportId,
      ]);

      // 리포트 마스터 삭제
      const result = await client.query(
        `DELETE FROM report_master WHERE report_id = $1`,
        [reportId]
      );

      return (result.rowCount ?? 0) > 0;
    });
  }

  /**
   * 리포트 복사
   */
  async copyReport(reportId: string, userId: string): Promise<string | null> {
    return transaction(async (client) => {
      // 원본 리포트 조회
      const originalQuery = `
        SELECT * FROM report_master WHERE report_id = $1
      `;
      const originalResult = await client.query(originalQuery, [reportId]);

      if (originalResult.rows.length === 0) {
        return null;
      }

      const original = originalResult.rows[0];
      const newReportId = `RPT_${uuidv4().replace(/-/g, "").substring(0, 20)}`;

      // 리포트 마스터 복사
      const copyReportQuery = `
        INSERT INTO report_master (
          report_id,
          report_name_kor,
          report_name_eng,
          template_id,
          report_type,
          company_code,
          description,
          use_yn,
          created_by
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
      `;

      await client.query(copyReportQuery, [
        newReportId,
        `${original.report_name_kor} (복사)`,
        original.report_name_eng ? `${original.report_name_eng} (Copy)` : null,
        original.template_id,
        original.report_type,
        original.company_code,
        original.description,
        original.use_yn,
        userId,
      ]);

      // 레이아웃 복사
      const layoutQuery = `
        SELECT * FROM report_layout WHERE report_id = $1
      `;
      const layoutResult = await client.query(layoutQuery, [reportId]);

      if (layoutResult.rows.length > 0) {
        const originalLayout = layoutResult.rows[0];
        const newLayoutId = `LAY_${uuidv4().replace(/-/g, "").substring(0, 20)}`;

        const copyLayoutQuery = `
          INSERT INTO report_layout (
            layout_id,
            report_id,
            canvas_width,
            canvas_height,
            page_orientation,
            margin_top,
            margin_bottom,
            margin_left,
            margin_right,
            components,
            created_by
          ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
        `;

        // components가 이미 문자열이면 그대로, 객체면 JSON.stringify
        const componentsData =
          typeof originalLayout.components === "string"
            ? originalLayout.components
            : JSON.stringify(originalLayout.components);

        await client.query(copyLayoutQuery, [
          newLayoutId,
          newReportId,
          originalLayout.canvas_width,
          originalLayout.canvas_height,
          originalLayout.page_orientation,
          originalLayout.margin_top,
          originalLayout.margin_bottom,
          originalLayout.margin_left,
          originalLayout.margin_right,
          componentsData,
          userId,
        ]);
      }

      // 쿼리 복사
      const queriesQuery = `
        SELECT * FROM report_query WHERE report_id = $1 ORDER BY display_order
      `;
      const queriesResult = await client.query(queriesQuery, [reportId]);

      if (queriesResult.rows.length > 0) {
        const copyQuerySql = `
          INSERT INTO report_query (
            query_id,
            report_id,
            query_name,
            query_type,
            sql_query,
            parameters,
            external_connection_id,
            display_order,
            created_by
          ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
        `;

        for (const originalQuery of queriesResult.rows) {
          const newQueryId = `QRY_${uuidv4().replace(/-/g, "").substring(0, 20)}`;
          await client.query(copyQuerySql, [
            newQueryId,
            newReportId,
            originalQuery.query_name,
            originalQuery.query_type,
            originalQuery.sql_query,
            JSON.stringify(originalQuery.parameters),
            originalQuery.external_connection_id || null,
            originalQuery.display_order,
            userId,
          ]);
        }
      }

      return newReportId;
    });
  }

  /**
   * 레이아웃 조회
   */
  async getLayout(reportId: string): Promise<ReportLayout | null> {
    const layoutQuery = `
      SELECT 
        layout_id,
        report_id,
        canvas_width,
        canvas_height,
        page_orientation,
        margin_top,
        margin_bottom,
        margin_left,
        margin_right,
        components,
        created_at,
        created_by,
        updated_at,
        updated_by
      FROM report_layout
      WHERE report_id = $1
    `;

    return queryOne<ReportLayout>(layoutQuery, [reportId]);
  }

  /**
   * 레이아웃 저장 (쿼리 포함) - 페이지 기반 구조
   */
  async saveLayout(
    reportId: string,
    data: SaveLayoutRequest,
    userId: string
  ): Promise<boolean> {
    return transaction(async (client) => {
      // 첫 번째 페이지 정보를 기본 레이아웃으로 사용
      const firstPage = data.layoutConfig.pages[0];
      const canvasWidth = firstPage?.width || 210;
      const canvasHeight = firstPage?.height || 297;
      const pageOrientation =
        canvasWidth > canvasHeight ? "landscape" : "portrait";
      const margins = firstPage?.margins || {
        top: 20,
        bottom: 20,
        left: 20,
        right: 20,
      };

      // 1. 레이아웃 저장
      const existingQuery = `
        SELECT layout_id FROM report_layout WHERE report_id = $1
      `;
      const existing = await client.query(existingQuery, [reportId]);

      if (existing.rows.length > 0) {
        // 업데이트 - components 컬럼에 전체 layoutConfig 저장
        const updateQuery = `
          UPDATE report_layout
          SET 
            canvas_width = $1,
            canvas_height = $2,
            page_orientation = $3,
            margin_top = $4,
            margin_bottom = $5,
            margin_left = $6,
            margin_right = $7,
            components = $8,
            updated_at = CURRENT_TIMESTAMP,
            updated_by = $9
          WHERE report_id = $10
        `;

        await client.query(updateQuery, [
          canvasWidth,
          canvasHeight,
          pageOrientation,
          margins.top,
          margins.bottom,
          margins.left,
          margins.right,
          JSON.stringify(data.layoutConfig), // 전체 layoutConfig 저장
          userId,
          reportId,
        ]);
      } else {
        // 생성
        const layoutId = `LAY_${uuidv4().replace(/-/g, "").substring(0, 20)}`;
        const insertQuery = `
          INSERT INTO report_layout (
            layout_id,
            report_id,
            canvas_width,
            canvas_height,
            page_orientation,
            margin_top,
            margin_bottom,
            margin_left,
            margin_right,
            components,
            created_by
          ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
        `;

        await client.query(insertQuery, [
          layoutId,
          reportId,
          canvasWidth,
          canvasHeight,
          pageOrientation,
          margins.top,
          margins.bottom,
          margins.left,
          margins.right,
          JSON.stringify(data.layoutConfig), // 전체 layoutConfig 저장
          userId,
        ]);
      }

      // 2. 쿼리 저장 (있는 경우)
      if (data.queries && data.queries.length > 0) {
        // 기존 쿼리 모두 삭제
        await client.query(`DELETE FROM report_query WHERE report_id = $1`, [
          reportId,
        ]);

        // 새 쿼리 삽입
        const insertQuerySql = `
          INSERT INTO report_query (
            query_id,
            report_id,
            query_name,
            query_type,
            sql_query,
            parameters,
            external_connection_id,
            display_order,
            created_by
          ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
        `;

        for (let i = 0; i < data.queries.length; i++) {
          const q = data.queries[i];
          await client.query(insertQuerySql, [
            q.id,
            reportId,
            q.name,
            q.type,
            q.sqlQuery,
            JSON.stringify(q.parameters),
            (q as any).externalConnectionId || null, // 외부 DB 연결 ID
            i,
            userId,
          ]);
        }
      }

      // 3. 메뉴 매핑 저장 (있는 경우)
      if (data.menuObjids !== undefined) {
        // 기존 메뉴 매핑 모두 삭제
        await client.query(
          `DELETE FROM report_menu_mapping WHERE report_id = $1`,
          [reportId]
        );

        // 새 메뉴 매핑 삽입
        if (data.menuObjids.length > 0) {
          // 리포트의 company_code 조회
          const reportResult = await client.query(
            `SELECT company_code FROM report_master WHERE report_id = $1`,
            [reportId]
          );
          const companyCode = reportResult.rows[0]?.company_code || "*";

          const insertMappingSql = `
            INSERT INTO report_menu_mapping (
              report_id,
              menu_objid,
              company_code,
              created_by
            ) VALUES ($1, $2, $3, $4)
          `;

          for (const menuObjid of data.menuObjids) {
            await client.query(insertMappingSql, [
              reportId,
              menuObjid,
              companyCode,
              userId,
            ]);
          }
        }
      }

      return true;
    });
  }

  /**
   * 쿼리 실행 (내부 DB 또는 외부 DB)
   */
  async executeQuery(
    reportId: string,
    queryId: string,
    parameters: Record<string, any>,
    sqlQuery?: string,
    externalConnectionId?: number | null
  ): Promise<{ fields: string[]; rows: any[] }> {
    let sql_query: string;
    let queryParameters: string[] = [];
    let connectionId: number | null = externalConnectionId ?? null;

    // 테스트 모드 (sqlQuery 직접 전달)
    if (sqlQuery) {
      sql_query = sqlQuery;
      // 파라미터 순서 추출 (등장 순서대로)
      const matches = sqlQuery.match(/\$\d+/g);
      if (matches) {
        const seen = new Set<string>();
        const result: string[] = [];
        for (const match of matches) {
          if (!seen.has(match)) {
            seen.add(match);
            result.push(match);
          }
        }
        queryParameters = result;
      }
    } else {
      // DB에서 쿼리 조회
      const queryResult = await queryOne<ReportQuery>(
        `SELECT * FROM report_query WHERE query_id = $1 AND report_id = $2`,
        [queryId, reportId]
      );

      if (!queryResult) {
        throw new Error("쿼리를 찾을 수 없습니다.");
      }

      sql_query = queryResult.sql_query;
      queryParameters = Array.isArray(queryResult.parameters)
        ? queryResult.parameters
        : [];
      connectionId = queryResult.external_connection_id;
    }

    // SQL 쿼리 안전성 검증 (SELECT만 허용)
    this.validateQuerySafety(sql_query);

    // 파라미터 배열 생성 ($1, $2 순서대로)
    const paramArray: any[] = [];
    for (const param of queryParameters) {
      paramArray.push(parameters[param] || null);
    }

    try {
      let result: any[];

      // 외부 DB 연결이 있으면 외부 DB에서 실행
      if (connectionId) {
        // 외부 DB 연결 정보 조회
        const connectionResult =
          await ExternalDbConnectionService.getConnectionById(connectionId);

        if (!connectionResult.success || !connectionResult.data) {
          throw new Error("외부 DB 연결 정보를 찾을 수 없습니다.");
        }

        const connection = connectionResult.data;

        // DatabaseConnectorFactory를 사용하여 외부 DB 쿼리 실행
        const config = {
          host: connection.host,
          port: connection.port,
          database: connection.database_name,
          user: connection.username,
          password: connection.password,
          connectionTimeout: connection.connection_timeout || 30000,
          queryTimeout: connection.query_timeout || 30000,
        };

        const connector = await DatabaseConnectorFactory.createConnector(
          connection.db_type,
          config,
          connectionId
        );

        await connector.connect();

        try {
          const queryResult = await connector.executeQuery(sql_query);
          result = queryResult.rows || [];
        } finally {
          await connector.disconnect();
        }
      } else {
        // 내부 DB에서 실행
        result = await query(sql_query, paramArray);
      }

      // 필드명 추출
      const fields = result.length > 0 ? Object.keys(result[0]) : [];

      return {
        fields,
        rows: result,
      };
    } catch (error: any) {
      throw new Error(`쿼리 실행 오류: ${error.message}`);
    }
  }

  /**
   * 템플릿 목록 조회
   */
  async getTemplates(): Promise<GetTemplatesResponse> {
    const templateQuery = `
      SELECT 
        template_id,
        template_name_kor,
        template_name_eng,
        template_type,
        is_system,
        thumbnail_url,
        description,
        layout_config,
        default_queries,
        use_yn,
        sort_order,
        created_at,
        created_by,
        updated_at,
        updated_by
      FROM report_template
      WHERE use_yn = 'Y'
      ORDER BY is_system DESC, sort_order ASC
    `;

    const templates = await query<ReportTemplate>(templateQuery);

    const system = templates.filter((t) => t.is_system === "Y");
    const custom = templates.filter((t) => t.is_system === "N");

    return { system, custom };
  }

  /**
   * 템플릿 생성 (사용자 정의)
   */
  async createTemplate(
    data: CreateTemplateRequest,
    userId: string
  ): Promise<string> {
    const templateId = `TPL_${uuidv4().replace(/-/g, "").substring(0, 20)}`;

    const insertQuery = `
      INSERT INTO report_template (
        template_id,
        template_name_kor,
        template_name_eng,
        template_type,
        is_system,
        description,
        layout_config,
        default_queries,
        use_yn,
        created_by
      ) VALUES ($1, $2, $3, $4, 'N', $5, $6, $7, 'Y', $8)
    `;

    await query(insertQuery, [
      templateId,
      data.templateNameKor,
      data.templateNameEng || null,
      data.templateType,
      data.description || null,
      data.layoutConfig ? JSON.stringify(data.layoutConfig) : null,
      data.defaultQueries ? JSON.stringify(data.defaultQueries) : null,
      userId,
    ]);

    return templateId;
  }

  /**
   * 템플릿 삭제 (사용자 정의만 가능)
   */
  async deleteTemplate(templateId: string): Promise<boolean> {
    const deleteQuery = `
      DELETE FROM report_template
      WHERE template_id = $1 AND is_system = 'N'
    `;

    const result = await query(deleteQuery, [templateId]);
    return true;
  }

  /**
   * 현재 리포트를 템플릿으로 저장
   */
  async saveAsTemplate(
    reportId: string,
    templateNameKor: string,
    templateNameEng: string | null | undefined,
    description: string | null | undefined,
    userId: string
  ): Promise<string> {
    return transaction(async (client) => {
      // 리포트 정보 조회
      const reportQuery = `
        SELECT report_type FROM report_master WHERE report_id = $1
      `;
      const reportResult = await client.query(reportQuery, [reportId]);

      if (reportResult.rows.length === 0) {
        throw new Error("리포트를 찾을 수 없습니다.");
      }

      const reportType = reportResult.rows[0].report_type;

      // 레이아웃 조회
      const layoutQuery = `
        SELECT 
          canvas_width,
          canvas_height,
          page_orientation,
          margin_top,
          margin_bottom,
          margin_left,
          margin_right,
          components
        FROM report_layout
        WHERE report_id = $1
      `;
      const layoutResult = await client.query(layoutQuery, [reportId]);

      if (layoutResult.rows.length === 0) {
        throw new Error("레이아웃을 찾을 수 없습니다.");
      }

      const layout = layoutResult.rows[0];

      // 쿼리 조회
      const queriesQuery = `
        SELECT 
          query_name,
          query_type,
          sql_query,
          parameters,
          external_connection_id,
          display_order
        FROM report_query
        WHERE report_id = $1
        ORDER BY display_order
      `;
      const queriesResult = await client.query(queriesQuery, [reportId]);

      // 레이아웃 설정 JSON 생성
      const layoutConfig = {
        width: layout.canvas_width,
        height: layout.canvas_height,
        orientation: layout.page_orientation,
        margins: {
          top: layout.margin_top,
          bottom: layout.margin_bottom,
          left: layout.margin_left,
          right: layout.margin_right,
        },
        components: JSON.parse(layout.components || "[]"),
      };

      // 기본 쿼리 JSON 생성
      const defaultQueries = queriesResult.rows.map((q) => ({
        name: q.query_name,
        type: q.query_type,
        sqlQuery: q.sql_query,
        parameters: Array.isArray(q.parameters) ? q.parameters : [],
        externalConnectionId: q.external_connection_id,
        displayOrder: q.display_order,
      }));

      // 템플릿 생성
      const templateId = `TPL_${uuidv4().replace(/-/g, "").substring(0, 20)}`;

      const insertQuery = `
        INSERT INTO report_template (
          template_id,
          template_name_kor,
          template_name_eng,
          template_type,
          is_system,
          description,
          layout_config,
          default_queries,
          use_yn,
          sort_order,
          created_by
        ) VALUES ($1, $2, $3, $4, 'N', $5, $6, $7, 'Y', 999, $8)
      `;

      await client.query(insertQuery, [
        templateId,
        templateNameKor,
        templateNameEng || null,
        reportType,
        description || null,
        JSON.stringify(layoutConfig),
        JSON.stringify(defaultQueries),
        userId,
      ]);

      return templateId;
    });
  }

  // 레이아웃 데이터로 직접 템플릿 생성 (리포트 저장 불필요)
  async createTemplateFromLayout(
    templateNameKor: string,
    templateNameEng: string | null | undefined,
    templateType: string,
    description: string | null | undefined,
    layoutConfig: {
      width: number;
      height: number;
      orientation: string;
      margins: {
        top: number;
        bottom: number;
        left: number;
        right: number;
      };
      components: any[];
    },
    defaultQueries: Array<{
      name: string;
      type: "MASTER" | "DETAIL";
      sqlQuery: string;
      parameters: string[];
      externalConnectionId?: number | null;
      displayOrder?: number;
    }>,
    userId: string
  ): Promise<string> {
    const templateId = `TPL_${uuidv4().replace(/-/g, "").substring(0, 20)}`;

    const insertQuery = `
      INSERT INTO report_template (
        template_id,
        template_name_kor,
        template_name_eng,
        template_type,
        is_system,
        description,
        layout_config,
        default_queries,
        use_yn,
        sort_order,
        created_by
      ) VALUES ($1, $2, $3, $4, 'N', $5, $6, $7, 'Y', 999, $8)
      RETURNING template_id
    `;

    await query(insertQuery, [
      templateId,
      templateNameKor,
      templateNameEng || null,
      templateType,
      description || null,
      JSON.stringify(layoutConfig),
      JSON.stringify(defaultQueries),
      userId,
    ]);

    return templateId;
  }
}

export default new ReportService();
