// 배치관리 전용 서비스 (기존 소스와 완전 분리)
// 작성일: 2024-12-24

import { query, queryOne } from "../database/db";
import { PasswordEncryption } from "../utils/passwordEncryption";
import { DatabaseConnectorFactory } from "../database/DatabaseConnectorFactory";

// 배치관리 전용 타입 정의
export interface BatchConnectionInfo {
  type: "internal" | "external";
  id?: number;
  name: string;
  db_type?: string;
}

export interface BatchTableInfo {
  table_name: string;
  columns: BatchColumnInfo[];
  description?: string | null;
}

export interface BatchColumnInfo {
  column_name: string;
  data_type: string;
  is_nullable?: string;
  column_default?: string | null;
}

export interface BatchApiResponse<T = unknown> {
  success: boolean;
  data?: T;
  message?: string;
  error?: string;
}

export class BatchManagementService {
  /**
   * 배치관리용 연결 목록 조회 (회사별)
   */
  static async getAvailableConnections(
    userCompanyCode?: string
  ): Promise<BatchApiResponse<BatchConnectionInfo[]>> {
    try {
      const connections: BatchConnectionInfo[] = [];

      // 내부 DB 추가
      connections.push({
        type: "internal",
        name: "내부 데이터베이스 (PostgreSQL)",
        db_type: "postgresql",
      });

      // 활성화된 외부 DB 연결 조회 (회사별 필터링)
      let query_sql = `SELECT id, connection_name, db_type, description
        FROM external_db_connections
        WHERE is_active = 'Y'`;

      const params: any[] = [];

      // 회사별 필터링 (최고 관리자가 아닌 경우)
      if (userCompanyCode && userCompanyCode !== "*") {
        query_sql += ` AND company_code = $1`;
        params.push(userCompanyCode);
      }

      query_sql += ` ORDER BY connection_name ASC`;

      const externalConnections = await query<{
        id: number;
        connection_name: string;
        db_type: string;
        description: string;
      }>(query_sql, params);

      // 외부 DB 연결 추가
      externalConnections.forEach((conn) => {
        connections.push({
          type: "external",
          id: conn.id,
          name: `${conn.connection_name} (${conn.db_type?.toUpperCase()})`,
          db_type: conn.db_type || undefined,
        });
      });

      return {
        success: true,
        data: connections,
        message: `${connections.length}개의 연결을 조회했습니다.`,
      };
    } catch (error) {
      console.error("배치관리 연결 목록 조회 실패:", error);
      return {
        success: false,
        message: "연결 목록 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      };
    }
  }

  /**
   * 배치관리용 테이블 목록 조회 (회사별)
   */
  static async getTablesFromConnection(
    connectionType: "internal" | "external",
    connectionId?: number,
    userCompanyCode?: string
  ): Promise<BatchApiResponse<BatchTableInfo[]>> {
    try {
      let tables: BatchTableInfo[] = [];

      if (connectionType === "internal") {
        // 내부 DB 테이블 조회
        const result = await query<{ table_name: string }>(
          `SELECT table_name
          FROM information_schema.tables
          WHERE table_schema = 'public'
          AND table_type = 'BASE TABLE'
          ORDER BY table_name`,
          []
        );

        tables = result.map((row) => ({
          table_name: row.table_name,
          columns: [],
        }));
      } else if (connectionType === "external" && connectionId) {
        // 외부 DB 테이블 조회 (회사별 필터링)
        const tablesResult = await this.getExternalTables(
          connectionId,
          userCompanyCode
        );
        if (tablesResult.success && tablesResult.data) {
          tables = tablesResult.data;
        }
      }

      return {
        success: true,
        data: tables,
        message: `${tables.length}개의 테이블을 조회했습니다.`,
      };
    } catch (error) {
      console.error("배치관리 테이블 목록 조회 실패:", error);
      return {
        success: false,
        message: "테이블 목록 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      };
    }
  }

  /**
   * 배치관리용 테이블 컬럼 정보 조회 (회사별)
   */
  static async getTableColumns(
    connectionType: "internal" | "external",
    connectionId: number | undefined,
    tableName: string,
    userCompanyCode?: string
  ): Promise<BatchApiResponse<BatchColumnInfo[]>> {
    try {
      console.log(`[BatchManagementService] getTableColumns 호출:`, {
        connectionType,
        connectionId,
        tableName,
      });

      let columns: BatchColumnInfo[] = [];

      if (connectionType === "internal") {
        // 내부 DB 컬럼 조회
        console.log(
          `[BatchManagementService] 내부 DB 컬럼 조회 시작: ${tableName}`
        );

        const result = await query<{
          column_name: string;
          data_type: string;
          is_nullable: string;
          column_default: string | null;
        }>(
          `SELECT 
            column_name,
            data_type,
            is_nullable,
            column_default
          FROM information_schema.columns 
          WHERE table_schema = 'public' 
          AND table_name = $1
          ORDER BY ordinal_position`,
          [tableName]
        );

        console.log(`[BatchManagementService] 쿼리 결과:`, result);

        console.log(`[BatchManagementService] 내부 DB 컬럼 조회 결과:`, result);

        columns = result.map((row) => ({
          column_name: row.column_name,
          data_type: row.data_type,
          is_nullable: row.is_nullable,
          column_default: row.column_default,
        }));
      } else if (connectionType === "external" && connectionId) {
        // 외부 DB 컬럼 조회 (회사별 필터링)
        console.log(
          `[BatchManagementService] 외부 DB 컬럼 조회 시작: connectionId=${connectionId}, tableName=${tableName}`
        );

        const columnsResult = await this.getExternalTableColumns(
          connectionId,
          tableName,
          userCompanyCode
        );

        console.log(
          `[BatchManagementService] 외부 DB 컬럼 조회 결과:`,
          columnsResult
        );

        if (columnsResult.success && columnsResult.data) {
          columns = columnsResult.data;
        }
      }

      console.log(`[BatchManagementService] 최종 컬럼 목록:`, columns);
      return {
        success: true,
        data: columns,
        message: `${columns.length}개의 컬럼을 조회했습니다.`,
      };
    } catch (error) {
      console.error("[BatchManagementService] 컬럼 정보 조회 오류:", error);
      return {
        success: false,
        message: "컬럼 정보 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      };
    }
  }

  /**
   * 외부 DB 테이블 목록 조회 (내부 구현, 회사별)
   */
  private static async getExternalTables(
    connectionId: number,
    userCompanyCode?: string
  ): Promise<BatchApiResponse<BatchTableInfo[]>> {
    try {
      // 연결 정보 조회 (회사별 필터링)
      let query_sql = `SELECT * FROM external_db_connections WHERE id = $1`;
      const params: any[] = [connectionId];

      // 회사별 필터링 (최고 관리자가 아닌 경우)
      if (userCompanyCode && userCompanyCode !== "*") {
        query_sql += ` AND company_code = $2`;
        params.push(userCompanyCode);
      }

      const connection = await queryOne<any>(query_sql, params);

      if (!connection) {
        return {
          success: false,
          message: "연결 정보를 찾을 수 없거나 권한이 없습니다.",
        };
      }

      // 비밀번호 복호화
      const decryptedPassword = PasswordEncryption.decrypt(connection.password);
      if (!decryptedPassword) {
        return {
          success: false,
          message: "비밀번호 복호화에 실패했습니다.",
        };
      }

      // 연결 설정 준비
      const config = {
        host: connection.host,
        port: connection.port,
        database: connection.database_name,
        user: connection.username,
        password: decryptedPassword,
        connectionTimeoutMillis:
          connection.connection_timeout != null
            ? connection.connection_timeout * 1000
            : undefined,
        queryTimeoutMillis:
          connection.query_timeout != null
            ? connection.query_timeout * 1000
            : undefined,
        ssl:
          connection.ssl_enabled === "Y"
            ? { rejectUnauthorized: false }
            : false,
      };

      // DatabaseConnectorFactory를 통한 테이블 목록 조회
      const connector = await DatabaseConnectorFactory.createConnector(
        connection.db_type,
        config,
        connectionId
      );
      const tables = await connector.getTables();

      return {
        success: true,
        message: "테이블 목록을 조회했습니다.",
        data: tables,
      };
    } catch (error) {
      console.error("외부 DB 테이블 목록 조회 오류:", error);
      return {
        success: false,
        message: "테이블 목록 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      };
    }
  }

  /**
   * 외부 DB 테이블 컬럼 정보 조회 (내부 구현, 회사별)
   */
  private static async getExternalTableColumns(
    connectionId: number,
    tableName: string,
    userCompanyCode?: string
  ): Promise<BatchApiResponse<BatchColumnInfo[]>> {
    try {
      console.log(
        `[BatchManagementService] getExternalTableColumns 호출: connectionId=${connectionId}, tableName=${tableName}`
      );

      // 연결 정보 조회 (회사별 필터링)
      let query_sql = `SELECT * FROM external_db_connections WHERE id = $1`;
      const params: any[] = [connectionId];

      // 회사별 필터링 (최고 관리자가 아닌 경우)
      if (userCompanyCode && userCompanyCode !== "*") {
        query_sql += ` AND company_code = $2`;
        params.push(userCompanyCode);
      }

      const connection = await queryOne<any>(query_sql, params);

      if (!connection) {
        console.log(
          `[BatchManagementService] 연결 정보를 찾을 수 없거나 권한이 없음: connectionId=${connectionId}`
        );
        return {
          success: false,
          message: "연결 정보를 찾을 수 없습니다.",
        };
      }

      console.log(`[BatchManagementService] 연결 정보 조회 성공:`, {
        id: connection.id,
        connection_name: connection.connection_name,
        db_type: connection.db_type,
        host: connection.host,
        port: connection.port,
        database_name: connection.database_name,
      });

      // 비밀번호 복호화
      const decryptedPassword = PasswordEncryption.decrypt(connection.password);

      // 연결 설정 준비
      const config = {
        host: connection.host,
        port: connection.port,
        database: connection.database_name,
        user: connection.username,
        password: decryptedPassword,
        connectionTimeoutMillis:
          connection.connection_timeout != null
            ? connection.connection_timeout * 1000
            : undefined,
        queryTimeoutMillis:
          connection.query_timeout != null
            ? connection.query_timeout * 1000
            : undefined,
        ssl:
          connection.ssl_enabled === "Y"
            ? { rejectUnauthorized: false }
            : false,
      };

      console.log(
        `[BatchManagementService] 커넥터 생성 시작: db_type=${connection.db_type}`
      );

      // 데이터베이스 타입에 따른 커넥터 생성
      const connector = await DatabaseConnectorFactory.createConnector(
        connection.db_type,
        config,
        connectionId
      );

      console.log(
        `[BatchManagementService] 커넥터 생성 완료, 컬럼 조회 시작: tableName=${tableName}`
      );

      // 컬럼 정보 조회
      console.log(`[BatchManagementService] connector.getColumns 호출 전`);
      const columns = await connector.getColumns(tableName);

      console.log(`[BatchManagementService] 원본 컬럼 조회 결과:`, columns);
      console.log(
        `[BatchManagementService] 원본 컬럼 개수:`,
        columns ? columns.length : "null/undefined"
      );

      // 각 데이터베이스 커넥터의 반환 구조가 다르므로 통일된 구조로 변환
      const standardizedColumns: BatchColumnInfo[] = columns.map((col: any) => {
        console.log(`[BatchManagementService] 컬럼 변환 중:`, col);

        // MySQL/MariaDB 구조: {name, dataType, isNullable, defaultValue} (MySQLConnector만)
        if (col.name && col.dataType !== undefined) {
          const result = {
            column_name: col.name,
            data_type: col.dataType,
            is_nullable: col.isNullable ? "YES" : "NO",
            column_default: col.defaultValue || null,
          };
          console.log(
            `[BatchManagementService] MySQL/MariaDB 구조로 변환:`,
            result
          );
          return result;
        }
        // PostgreSQL/Oracle/MSSQL/MariaDB 구조: {column_name, data_type, is_nullable, column_default}
        else {
          const result = {
            column_name: col.column_name || col.COLUMN_NAME,
            data_type: col.data_type || col.DATA_TYPE,
            is_nullable:
              col.is_nullable ||
              col.IS_NULLABLE ||
              (col.nullable === "Y" ? "YES" : "NO"),
            column_default: col.column_default || col.COLUMN_DEFAULT || null,
          };
          console.log(`[BatchManagementService] 표준 구조로 변환:`, result);
          return result;
        }
      });

      console.log(
        `[BatchManagementService] 표준화된 컬럼 목록:`,
        standardizedColumns
      );

      return {
        success: true,
        data: standardizedColumns,
        message: "컬럼 정보를 조회했습니다.",
      };
    } catch (error) {
      console.error(
        "[BatchManagementService] 외부 DB 컬럼 정보 조회 오류:",
        error
      );
      console.error(
        "[BatchManagementService] 오류 스택:",
        error instanceof Error ? error.stack : "No stack trace"
      );
      return {
        success: false,
        message: "컬럼 정보 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      };
    }
  }
}
