import { getPool } from "../database/db";
import { logger } from "../utils/logger";
import crypto from "crypto";

export interface ExcelMappingTemplate {
  id?: number;
  tableName: string;
  excelColumns: string[];
  excelColumnsHash: string;
  columnMappings: Record<string, string | null>; // { "엑셀컬럼": "시스템컬럼" }
  companyCode: string;
  createdDate?: Date;
  updatedDate?: Date;
}

class ExcelMappingService {
  /**
   * 엑셀 컬럼 목록으로 해시 생성
   * 정렬 후 MD5 해시 생성하여 동일한 컬럼 구조 식별
   */
  generateColumnsHash(columns: string[]): string {
    // 컬럼 목록을 정렬하여 순서와 무관하게 동일한 해시 생성
    const sortedColumns = [...columns].sort();
    const columnsString = sortedColumns.join("|");
    return crypto.createHash("md5").update(columnsString).digest("hex");
  }

  /**
   * 엑셀 컬럼 구조로 매핑 템플릿 조회
   * 동일한 컬럼 구조가 있으면 기존 매핑 반환
   */
  async findMappingByColumns(
    tableName: string,
    excelColumns: string[],
    companyCode: string
  ): Promise<ExcelMappingTemplate | null> {
    try {
      const hash = this.generateColumnsHash(excelColumns);

      logger.info("엑셀 매핑 템플릿 조회", {
        tableName,
        excelColumns,
        hash,
        companyCode,
      });

      const pool = getPool();

      // 회사별 매핑 먼저 조회, 없으면 공통(*) 매핑 조회
      let query: string;
      let params: any[];

      if (companyCode === "*") {
        query = `
          SELECT 
            id,
            table_name as "tableName",
            excel_columns as "excelColumns",
            excel_columns_hash as "excelColumnsHash",
            column_mappings as "columnMappings",
            company_code as "companyCode",
            created_date as "createdDate",
            updated_date as "updatedDate"
          FROM excel_mapping_template
          WHERE table_name = $1
            AND excel_columns_hash = $2
          ORDER BY updated_date DESC
          LIMIT 1
        `;
        params = [tableName, hash];
      } else {
        query = `
          SELECT 
            id,
            table_name as "tableName",
            excel_columns as "excelColumns",
            excel_columns_hash as "excelColumnsHash",
            column_mappings as "columnMappings",
            company_code as "companyCode",
            created_date as "createdDate",
            updated_date as "updatedDate"
          FROM excel_mapping_template
          WHERE table_name = $1
            AND excel_columns_hash = $2
            AND (company_code = $3 OR company_code = '*')
          ORDER BY 
            CASE WHEN company_code = $3 THEN 0 ELSE 1 END,
            updated_date DESC
          LIMIT 1
        `;
        params = [tableName, hash, companyCode];
      }

      const result = await pool.query(query, params);

      if (result.rows.length > 0) {
        logger.info("기존 매핑 템플릿 발견", {
          id: result.rows[0].id,
          tableName,
        });
        return result.rows[0];
      }

      logger.info("매핑 템플릿 없음 - 새 구조", { tableName, hash });
      return null;
    } catch (error: any) {
      logger.error(`매핑 템플릿 조회 실패: ${error.message}`, { error });
      throw error;
    }
  }

  /**
   * 매핑 템플릿 저장 (UPSERT)
   * 동일한 테이블+컬럼구조+회사코드가 있으면 업데이트, 없으면 삽입
   */
  async saveMappingTemplate(
    tableName: string,
    excelColumns: string[],
    columnMappings: Record<string, string | null>,
    companyCode: string,
    userId?: string
  ): Promise<ExcelMappingTemplate> {
    try {
      const hash = this.generateColumnsHash(excelColumns);

      logger.info("엑셀 매핑 템플릿 저장 (UPSERT)", {
        tableName,
        excelColumns,
        hash,
        columnMappings,
        companyCode,
      });

      const pool = getPool();

      const query = `
        INSERT INTO excel_mapping_template (
          table_name,
          excel_columns,
          excel_columns_hash,
          column_mappings,
          company_code,
          created_date,
          updated_date
        ) VALUES ($1, $2, $3, $4, $5, NOW(), NOW())
        ON CONFLICT (table_name, excel_columns_hash, company_code)
        DO UPDATE SET
          column_mappings = EXCLUDED.column_mappings,
          updated_date = NOW()
        RETURNING 
          id,
          table_name as "tableName",
          excel_columns as "excelColumns",
          excel_columns_hash as "excelColumnsHash",
          column_mappings as "columnMappings",
          company_code as "companyCode",
          created_date as "createdDate",
          updated_date as "updatedDate"
      `;

      const result = await pool.query(query, [
        tableName,
        excelColumns,
        hash,
        JSON.stringify(columnMappings),
        companyCode,
      ]);

      logger.info("매핑 템플릿 저장 완료", {
        id: result.rows[0].id,
        tableName,
        hash,
      });

      return result.rows[0];
    } catch (error: any) {
      logger.error(`매핑 템플릿 저장 실패: ${error.message}`, { error });
      throw error;
    }
  }

  /**
   * 테이블의 모든 매핑 템플릿 조회
   */
  async getMappingTemplates(
    tableName: string,
    companyCode: string
  ): Promise<ExcelMappingTemplate[]> {
    try {
      logger.info("테이블 매핑 템플릿 목록 조회", { tableName, companyCode });

      const pool = getPool();

      let query: string;
      let params: any[];

      if (companyCode === "*") {
        query = `
          SELECT 
            id,
            table_name as "tableName",
            excel_columns as "excelColumns",
            excel_columns_hash as "excelColumnsHash",
            column_mappings as "columnMappings",
            company_code as "companyCode",
            created_date as "createdDate",
            updated_date as "updatedDate"
          FROM excel_mapping_template
          WHERE table_name = $1
          ORDER BY updated_date DESC
        `;
        params = [tableName];
      } else {
        query = `
          SELECT 
            id,
            table_name as "tableName",
            excel_columns as "excelColumns",
            excel_columns_hash as "excelColumnsHash",
            column_mappings as "columnMappings",
            company_code as "companyCode",
            created_date as "createdDate",
            updated_date as "updatedDate"
          FROM excel_mapping_template
          WHERE table_name = $1
            AND (company_code = $2 OR company_code = '*')
          ORDER BY updated_date DESC
        `;
        params = [tableName, companyCode];
      }

      const result = await pool.query(query, params);

      logger.info(`매핑 템플릿 ${result.rows.length}개 조회`, { tableName });

      return result.rows;
    } catch (error: any) {
      logger.error(`매핑 템플릿 목록 조회 실패: ${error.message}`, { error });
      throw error;
    }
  }

  /**
   * 매핑 템플릿 삭제
   */
  async deleteMappingTemplate(
    id: number,
    companyCode: string
  ): Promise<boolean> {
    try {
      logger.info("매핑 템플릿 삭제", { id, companyCode });

      const pool = getPool();

      let query: string;
      let params: any[];

      if (companyCode === "*") {
        query = `DELETE FROM excel_mapping_template WHERE id = $1`;
        params = [id];
      } else {
        query = `DELETE FROM excel_mapping_template WHERE id = $1 AND company_code = $2`;
        params = [id, companyCode];
      }

      const result = await pool.query(query, params);

      if (result.rowCount && result.rowCount > 0) {
        logger.info("매핑 템플릿 삭제 완료", { id });
        return true;
      }

      logger.warn("삭제할 매핑 템플릿 없음", { id, companyCode });
      return false;
    } catch (error: any) {
      logger.error(`매핑 템플릿 삭제 실패: ${error.message}`, { error });
      throw error;
    }
  }
}

export default new ExcelMappingService();

