/**
 * 다중 커넥션 쿼리 실행 서비스
 * 외부 데이터베이스 커넥션을 통한 CRUD 작업 지원
 * 자기 자신 테이블 작업을 위한 안전장치 포함
 */

import { ExternalDbConnectionService } from "./externalDbConnectionService";
import { TableManagementService } from "./tableManagementService";
import { ExternalDbConnection, ApiResponse } from "../types/externalDbTypes";
import { ColumnTypeInfo, TableInfo } from "../types/tableManagement";
import { query } from "../database/db";
import { logger } from "../utils/logger";

// 🔧 Prisma 클라이언트 중복 생성 방지 - 기존 인스턴스 재사용

export interface ValidationResult {
  isValid: boolean;
  error?: string;
  warnings?: string[];
}

export interface ColumnInfo {
  columnName: string;
  displayName: string;
  dataType: string;
  dbType: string;
  webType: string;
  isNullable: boolean;
  isPrimaryKey: boolean;
  defaultValue?: string;
  maxLength?: number;
  description?: string;
}

export interface MultiConnectionTableInfo {
  tableName: string;
  displayName?: string;
  columnCount: number;
  connectionId: number;
  connectionName: string;
  dbType: string;
}

export class MultiConnectionQueryService {
  private tableManagementService: TableManagementService;

  constructor() {
    this.tableManagementService = new TableManagementService();
  }

  /**
   * 소스 커넥션에서 데이터 조회
   */
  async fetchDataFromConnection(
    connectionId: number,
    tableName: string,
    conditions?: Record<string, any>
  ): Promise<Record<string, any>[]> {
    try {
      logger.info(
        `데이터 조회 시작: connectionId=${connectionId}, table=${tableName}`
      );

      // connectionId가 0이면 메인 DB 사용
      if (connectionId === 0) {
        return await this.executeOnMainDatabase(
          "select",
          tableName,
          undefined,
          conditions
        );
      }

      // 외부 DB 연결 정보 가져오기
      const connectionResult =
        await ExternalDbConnectionService.getConnectionById(connectionId);
      if (!connectionResult.success || !connectionResult.data) {
        throw new Error(`커넥션을 찾을 수 없습니다: ${connectionId}`);
      }
      const connection = connectionResult.data;

      // 쿼리 조건 구성
      let whereClause = "";
      const queryParams: any[] = [];

      if (conditions && Object.keys(conditions).length > 0) {
        const conditionParts: string[] = [];
        let paramIndex = 1;

        Object.entries(conditions).forEach(([key, value]) => {
          conditionParts.push(`${key} = $${paramIndex}`);
          queryParams.push(value);
          paramIndex++;
        });

        whereClause = `WHERE ${conditionParts.join(" AND ")}`;
      }

      const query = `SELECT * FROM ${tableName} ${whereClause}`;

      // 외부 DB에서 쿼리 실행
      const result = await ExternalDbConnectionService.executeQuery(
        connectionId,
        query
      );

      if (!result.success || !result.data) {
        throw new Error(result.message || "쿼리 실행 실패");
      }

      logger.info(`데이터 조회 완료: ${result.data.length}건`);
      return result.data;
    } catch (error) {
      logger.error(`데이터 조회 실패: ${error}`);
      throw new Error(
        `데이터 조회 실패: ${error instanceof Error ? error.message : error}`
      );
    }
  }

  /**
   * 대상 커넥션에 데이터 삽입
   */
  async insertDataToConnection(
    connectionId: number,
    tableName: string,
    data: Record<string, any>
  ): Promise<any> {
    try {
      logger.info(
        `데이터 삽입 시작: connectionId=${connectionId}, table=${tableName}`
      );

      // connectionId가 0이면 메인 DB 사용
      if (connectionId === 0) {
        return await this.executeOnMainDatabase("insert", tableName, data);
      }

      // 외부 DB 연결 정보 가져오기
      const connectionResult =
        await ExternalDbConnectionService.getConnectionById(connectionId);
      if (!connectionResult.success || !connectionResult.data) {
        throw new Error(`커넥션을 찾을 수 없습니다: ${connectionId}`);
      }
      const connection = connectionResult.data;

      // INSERT 쿼리 구성 (DB 타입별 처리)
      const columns = Object.keys(data);
      let values = Object.values(data);

      // Oracle의 경우 테이블 스키마 확인 및 데이터 타입 변환 처리
      if (connection.db_type?.toLowerCase() === "oracle") {
        try {
          // Oracle 테이블 스키마 조회
          const schemaQuery = `
            SELECT COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT
            FROM USER_TAB_COLUMNS 
            WHERE TABLE_NAME = UPPER('${tableName}')
            ORDER BY COLUMN_ID
          `;

          logger.info(`🔍 Oracle 테이블 스키마 조회: ${schemaQuery}`);

          const schemaResult = await ExternalDbConnectionService.executeQuery(
            connectionId,
            schemaQuery
          );

          if (schemaResult.success && schemaResult.data) {
            logger.info(`📋 Oracle 테이블 ${tableName} 스키마:`);
            schemaResult.data.forEach((col: any) => {
              logger.info(
                `  - ${col.COLUMN_NAME}: ${col.DATA_TYPE}, NULL: ${col.NULLABLE}, DEFAULT: ${col.DATA_DEFAULT || "None"}`
              );
            });

            // 필수 컬럼 중 누락된 컬럼이 있는지 확인 (기본값이 없는 NOT NULL 컬럼만)
            const providedColumns = columns.map((col) => col.toUpperCase());
            const missingRequiredColumns = schemaResult.data.filter(
              (schemaCol: any) =>
                schemaCol.NULLABLE === "N" &&
                !schemaCol.DATA_DEFAULT &&
                !providedColumns.includes(schemaCol.COLUMN_NAME)
            );

            if (missingRequiredColumns.length > 0) {
              const missingNames = missingRequiredColumns.map(
                (col: any) => col.COLUMN_NAME
              );
              logger.error(`❌ 필수 컬럼 누락: ${missingNames.join(", ")}`);
              throw new Error(
                `필수 컬럼이 누락되었습니다: ${missingNames.join(", ")}`
              );
            }

            logger.info(
              `✅ 스키마 검증 통과: 모든 필수 컬럼이 제공되었거나 기본값이 있습니다.`
            );
          }
        } catch (schemaError) {
          logger.warn(`⚠️ 스키마 조회 실패 (계속 진행): ${schemaError}`);
        }

        values = values.map((value) => {
          // null이나 undefined는 그대로 유지
          if (value === null || value === undefined) {
            return value;
          }

          // 숫자로 변환 가능한 문자열은 숫자로 변환
          if (typeof value === "string" && value.trim() !== "") {
            const numValue = Number(value);
            if (!isNaN(numValue)) {
              logger.info(
                `🔄 Oracle 데이터 타입 변환: "${value}" (string) → ${numValue} (number)`
              );
              return numValue;
            }
          }

          return value;
        });
      }

      let query: string;
      let queryParams: any[];
      const dbType = connection.db_type?.toLowerCase() || "postgresql";

      switch (dbType) {
        case "oracle":
          // Oracle: :1, :2 스타일 바인딩 사용, RETURNING 미지원
          const oraclePlaceholders = values
            .map((_, index) => `:${index + 1}`)
            .join(", ");
          query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${oraclePlaceholders})`;
          queryParams = values;
          logger.info(`🔍 Oracle INSERT 상세 정보:`);
          logger.info(`  - 테이블: ${tableName}`);
          logger.info(`  - 컬럼: ${JSON.stringify(columns)}`);
          logger.info(`  - 값: ${JSON.stringify(values)}`);
          logger.info(`  - 쿼리: ${query}`);
          logger.info(`  - 파라미터: ${JSON.stringify(queryParams)}`);
          logger.info(
            `  - 데이터 타입: ${JSON.stringify(values.map((v) => typeof v))}`
          );
          break;

        case "mysql":
        case "mariadb":
          // MySQL/MariaDB: ? 스타일 바인딩 사용, RETURNING 미지원
          const mysqlPlaceholders = values.map(() => "?").join(", ");
          query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${mysqlPlaceholders})`;
          queryParams = values;
          logger.info(`MySQL/MariaDB INSERT 쿼리:`, {
            query,
            params: queryParams,
          });
          break;

        case "sqlserver":
        case "mssql":
          // SQL Server: @param1, @param2 스타일 바인딩 사용
          const sqlServerPlaceholders = values
            .map((_, index) => `@param${index + 1}`)
            .join(", ");
          query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${sqlServerPlaceholders})`;
          queryParams = values;
          logger.info(`SQL Server INSERT 쿼리:`, {
            query,
            params: queryParams,
          });
          break;

        case "sqlite":
          // SQLite: ? 스타일 바인딩 사용, RETURNING 지원 (3.35.0+)
          const sqlitePlaceholders = values.map(() => "?").join(", ");
          query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${sqlitePlaceholders}) RETURNING *`;
          queryParams = values;
          logger.info(`SQLite INSERT 쿼리:`, { query, params: queryParams });
          break;

        case "postgresql":
        default:
          // PostgreSQL: $1, $2 스타일 바인딩 사용, RETURNING 지원
          const pgPlaceholders = values
            .map((_, index) => `$${index + 1}`)
            .join(", ");
          query = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${pgPlaceholders}) RETURNING *`;
          queryParams = values;
          logger.info(`PostgreSQL INSERT 쿼리:`, {
            query,
            params: queryParams,
          });
          break;
      }

      // 외부 DB에서 쿼리 실행
      const result = await ExternalDbConnectionService.executeQuery(
        connectionId,
        query,
        queryParams
      );

      if (!result.success || !result.data) {
        throw new Error(result.message || "데이터 삽입 실패");
      }

      logger.info(`데이터 삽입 완료`);
      return result.data[0] || result.data;
    } catch (error) {
      logger.error(`데이터 삽입 실패: ${error}`);
      throw new Error(
        `데이터 삽입 실패: ${error instanceof Error ? error.message : error}`
      );
    }
  }

  /**
   * 🆕 대상 커넥션에 데이터 업데이트
   */
  async updateDataToConnection(
    connectionId: number,
    tableName: string,
    data: Record<string, any>,
    conditions: Record<string, any>
  ): Promise<any> {
    try {
      logger.info(
        `데이터 업데이트 시작: connectionId=${connectionId}, table=${tableName}`
      );

      // 자기 자신 테이블 작업 검증
      if (connectionId === 0) {
        const validationResult = await this.validateSelfTableOperation(
          tableName,
          "update",
          [conditions]
        );

        if (!validationResult.isValid) {
          throw new Error(
            `자기 자신 테이블 업데이트 검증 실패: ${validationResult.error}`
          );
        }
      }

      // connectionId가 0이면 메인 DB 사용
      if (connectionId === 0) {
        return await this.executeOnMainDatabase(
          "update",
          tableName,
          data,
          conditions
        );
      }

      // 외부 DB 연결 정보 가져오기
      const connectionResult =
        await ExternalDbConnectionService.getConnectionById(connectionId);
      if (!connectionResult.success || !connectionResult.data) {
        throw new Error(`커넥션을 찾을 수 없습니다: ${connectionId}`);
      }
      const connection = connectionResult.data;

      // UPDATE 쿼리 구성
      const setClause = Object.keys(data)
        .map((key, index) => `${key} = $${index + 1}`)
        .join(", ");

      const whereClause = Object.keys(conditions)
        .map(
          (key, index) => `${key} = $${Object.keys(data).length + index + 1}`
        )
        .join(" AND ");

      const query = `
        UPDATE ${tableName}
        SET ${setClause}
        WHERE ${whereClause}
        RETURNING *
      `;

      const queryParams = [
        ...Object.values(data),
        ...Object.values(conditions),
      ];

      // 외부 DB에서 쿼리 실행
      const result = await ExternalDbConnectionService.executeQuery(
        connectionId,
        query
      );

      if (!result.success || !result.data) {
        throw new Error(result.message || "데이터 업데이트 실패");
      }

      logger.info(`데이터 업데이트 완료: ${result.data.length}건`);
      return result.data;
    } catch (error) {
      logger.error(`데이터 업데이트 실패: ${error}`);
      throw new Error(
        `데이터 업데이트 실패: ${error instanceof Error ? error.message : error}`
      );
    }
  }

  /**
   * 🆕 대상 커넥션에서 데이터 삭제
   */
  async deleteDataFromConnection(
    connectionId: number,
    tableName: string,
    conditions: Record<string, any>,
    maxDeleteCount: number = 100
  ): Promise<any> {
    try {
      logger.info(
        `데이터 삭제 시작: connectionId=${connectionId}, table=${tableName}`
      );

      // 자기 자신 테이블 작업 검증
      if (connectionId === 0) {
        const validationResult = await this.validateSelfTableOperation(
          tableName,
          "delete",
          [conditions]
        );

        if (!validationResult.isValid) {
          throw new Error(
            `자기 자신 테이블 삭제 검증 실패: ${validationResult.error}`
          );
        }
      }

      // WHERE 조건 필수 체크
      if (!conditions || Object.keys(conditions).length === 0) {
        throw new Error("DELETE 작업에는 반드시 WHERE 조건이 필요합니다.");
      }

      // connectionId가 0이면 메인 DB 사용
      if (connectionId === 0) {
        return await this.executeOnMainDatabase(
          "delete",
          tableName,
          undefined,
          conditions
        );
      }

      // 외부 DB 연결 정보 가져오기
      const connectionResult =
        await ExternalDbConnectionService.getConnectionById(connectionId);
      if (!connectionResult.success || !connectionResult.data) {
        throw new Error(`커넥션을 찾을 수 없습니다: ${connectionId}`);
      }
      const connection = connectionResult.data;

      // 먼저 삭제 대상 개수 확인 (안전장치)
      const countQuery = `
        SELECT COUNT(*) as count
        FROM ${tableName}
        WHERE ${Object.keys(conditions)
          .map((key, index) => `${key} = $${index + 1}`)
          .join(" AND ")}
      `;

      const countResult = await ExternalDbConnectionService.executeQuery(
        connectionId,
        countQuery
      );

      if (!countResult.success || !countResult.data) {
        throw new Error(countResult.message || "삭제 대상 개수 조회 실패");
      }

      const deleteCount = parseInt(countResult.data[0]?.count || "0");

      if (deleteCount > maxDeleteCount) {
        throw new Error(
          `삭제 대상이 ${deleteCount}건으로 최대 허용 개수(${maxDeleteCount})를 초과합니다.`
        );
      }

      // DELETE 쿼리 실행
      const deleteQuery = `
        DELETE FROM ${tableName}
        WHERE ${Object.keys(conditions)
          .map((key, index) => `${key} = $${index + 1}`)
          .join(" AND ")}
        RETURNING *
      `;

      const result = await ExternalDbConnectionService.executeQuery(
        connectionId,
        deleteQuery
      );

      if (!result.success || !result.data) {
        throw new Error(result.message || "데이터 삭제 실패");
      }

      logger.info(`데이터 삭제 완료: ${result.data.length}건`);
      return result.data;
    } catch (error) {
      logger.error(`데이터 삭제 실패: ${error}`);
      throw new Error(
        `데이터 삭제 실패: ${error instanceof Error ? error.message : error}`
      );
    }
  }

  /**
   * 커넥션별 테이블 목록 조회
   */
  async getTablesFromConnection(
    connectionId: number
  ): Promise<MultiConnectionTableInfo[]> {
    try {
      logger.info(`테이블 목록 조회 시작: connectionId=${connectionId}`);

      // connectionId가 0이면 메인 DB의 테이블 목록 반환
      if (connectionId === 0) {
        const tables = await this.tableManagementService.getTableList();
        return tables.map((table) => ({
          tableName: table.tableName,
          displayName: table.displayName || table.tableName, // 라벨이 있으면 라벨 사용, 없으면 테이블명
          columnCount: table.columnCount,
          connectionId: 0,
          connectionName: "메인 데이터베이스",
          dbType: "postgresql",
        }));
      }

      // 외부 DB 연결 정보 가져오기
      const connectionResult =
        await ExternalDbConnectionService.getConnectionById(connectionId);
      if (!connectionResult.success || !connectionResult.data) {
        throw new Error(`커넥션을 찾을 수 없습니다: ${connectionId}`);
      }
      const connection = connectionResult.data;

      // 외부 DB의 테이블 목록 조회
      const tablesResult =
        await ExternalDbConnectionService.getTables(connectionId);
      if (!tablesResult.success || !tablesResult.data) {
        throw new Error(tablesResult.message || "테이블 조회 실패");
      }
      const tables = tablesResult.data;

      // 성능 최적화: 컬럼 개수는 실제 필요할 때만 조회하도록 변경
      return tables.map((table: any) => ({
        tableName: table.table_name,
        displayName: table.table_comment || table.table_name, // 라벨(comment)이 있으면 라벨 사용, 없으면 테이블명
        columnCount: 0, // 성능을 위해 0으로 설정, 필요시 별도 API로 조회
        connectionId: connectionId,
        connectionName: connection.connection_name,
        dbType: connection.db_type,
      }));
    } catch (error) {
      logger.error(`테이블 목록 조회 실패: ${error}`);
      throw new Error(
        `테이블 목록 조회 실패: ${error instanceof Error ? error.message : error}`
      );
    }
  }

  /**
   * 배치 테이블 정보 조회 (컬럼 수 포함)
   */
  async getBatchTablesWithColumns(
    connectionId: number
  ): Promise<
    { tableName: string; displayName?: string; columnCount: number }[]
  > {
    try {
      logger.info(`배치 테이블 정보 조회 시작: connectionId=${connectionId}`);

      // connectionId가 0이면 메인 DB
      if (connectionId === 0) {
        console.log("🔍 메인 DB 배치 테이블 정보 조회");

        // 메인 DB의 모든 테이블과 각 테이블의 컬럼 수 조회
        const tables = await this.tableManagementService.getTableList();

        const result = await Promise.all(
          tables.map(async (table) => {
            try {
              const columnsResult =
                await this.tableManagementService.getColumnList(
                  table.tableName,
                  1,
                  1000
                );

              return {
                tableName: table.tableName,
                displayName: table.displayName,
                columnCount: columnsResult.columns.length,
              };
            } catch (error) {
              logger.warn(
                `메인 DB 테이블 ${table.tableName} 컬럼 수 조회 실패:`,
                error
              );
              return {
                tableName: table.tableName,
                displayName: table.displayName,
                columnCount: 0,
              };
            }
          })
        );

        logger.info(`✅ 메인 DB 배치 조회 완료: ${result.length}개 테이블`);
        return result;
      }

      // 외부 DB 연결 정보 가져오기
      const connectionResult =
        await ExternalDbConnectionService.getConnectionById(connectionId);
      if (!connectionResult.success || !connectionResult.data) {
        throw new Error(`커넥션을 찾을 수 없습니다: ${connectionId}`);
      }
      const connection = connectionResult.data;

      console.log(
        `🔍 외부 DB 배치 테이블 정보 조회: connectionId=${connectionId}`
      );

      // 외부 DB의 테이블 목록 먼저 조회
      const tablesResult =
        await ExternalDbConnectionService.getTables(connectionId);

      if (!tablesResult.success || !tablesResult.data) {
        throw new Error("외부 DB 테이블 목록 조회 실패");
      }

      const tableNames = tablesResult.data;

      // 🔧 각 테이블의 컬럼 수를 순차적으로 조회 (타임아웃 방지)
      const result = [];
      logger.info(
        `📊 외부 DB 테이블 컬럼 조회 시작: ${tableNames.length}개 테이블`
      );

      for (let i = 0; i < tableNames.length; i++) {
        const tableInfo = tableNames[i];
        const tableName = tableInfo.table_name;

        try {
          logger.info(
            `📋 테이블 ${i + 1}/${tableNames.length}: ${tableName} 컬럼 조회 중...`
          );

          // 🔧 타임아웃과 재시도 로직 추가
          let columnsResult: ApiResponse<any[]> | undefined;
          let retryCount = 0;
          const maxRetries = 2;

          while (retryCount <= maxRetries) {
            try {
              columnsResult = (await Promise.race([
                ExternalDbConnectionService.getTableColumns(
                  connectionId,
                  tableName
                ),
                new Promise<ApiResponse<any[]>>((_, reject) =>
                  setTimeout(
                    () => reject(new Error("컬럼 조회 타임아웃 (15초)")),
                    15000
                  )
                ),
              ])) as ApiResponse<any[]>;
              break; // 성공하면 루프 종료
            } catch (attemptError) {
              retryCount++;
              if (retryCount > maxRetries) {
                throw attemptError; // 최대 재시도 후 에러 throw
              }
              logger.warn(
                `⚠️ 테이블 ${tableName} 컬럼 조회 실패 (${retryCount}/${maxRetries}), 재시도 중...`
              );
              await new Promise((resolve) => setTimeout(resolve, 1000)); // 1초 대기 후 재시도
            }
          }

          const columnCount =
            columnsResult &&
            columnsResult.success &&
            Array.isArray(columnsResult.data)
              ? columnsResult.data.length
              : 0;

          result.push({
            tableName,
            displayName: tableName, // 외부 DB는 일반적으로 displayName이 없음
            columnCount,
          });

          logger.info(`✅ 테이블 ${tableName}: ${columnCount}개 컬럼`);
        } catch (error) {
          const errorMessage =
            error instanceof Error ? error.message : String(error);
          logger.warn(
            `❌ 외부 DB 테이블 ${tableName} 컬럼 수 조회 최종 실패: ${errorMessage}`
          );
          result.push({
            tableName,
            displayName: tableName,
            columnCount: 0, // 실패한 경우 0으로 설정
          });
        }

        // 🔧 연결 부하 방지를 위한 약간의 지연
        if (i < tableNames.length - 1) {
          await new Promise((resolve) => setTimeout(resolve, 100)); // 100ms 지연
        }
      }

      logger.info(`✅ 외부 DB 배치 조회 완료: ${result.length}개 테이블`);
      return result;
    } catch (error) {
      logger.error(
        `배치 테이블 정보 조회 실패: connectionId=${connectionId}, error=${
          error instanceof Error ? error.message : error
        }`
      );
      throw error;
    }
  }

  /**
   * 커넥션별 컬럼 정보 조회
   */
  async getColumnsFromConnection(
    connectionId: number,
    tableName: string
  ): Promise<ColumnInfo[]> {
    try {
      logger.info(
        `컬럼 정보 조회 시작: connectionId=${connectionId}, table=${tableName}`
      );

      // connectionId가 0이면 메인 DB의 컬럼 정보 반환
      if (connectionId === 0) {
        console.log(`🔍 메인 DB 컬럼 정보 조회 시작: ${tableName}`);

        const columnsResult = await this.tableManagementService.getColumnList(
          tableName,
          1,
          1000
        );

        console.log(
          `✅ 메인 DB 컬럼 조회 성공: ${columnsResult.columns.length}개`
        );

        // 디버깅: inputType이 'code'인 컬럼들 확인
        const codeColumns = columnsResult.columns.filter(
          (col) => col.inputType === "code"
        );
        console.log(
          "🔍 메인 DB 코드 타입 컬럼들:",
          codeColumns.map((col) => ({
            columnName: col.columnName,
            inputType: col.inputType,
            webType: col.webType,
            codeCategory: col.codeCategory,
          }))
        );

        const mappedColumns = columnsResult.columns.map((column) => ({
          columnName: column.columnName,
          displayName: column.displayName || column.columnName, // 라벨이 있으면 라벨 사용, 없으면 컬럼명
          dataType: column.dataType,
          dbType: column.dataType, // dataType을 dbType으로 사용
          webType: column.webType || "text", // webType 사용, 기본값 text
          inputType: column.inputType || "direct", // table_type_columns의 input_type 추가
          codeCategory: column.codeCategory, // 코드 카테고리 정보 추가
          isNullable: column.isNullable === "Y",
          isPrimaryKey: column.isPrimaryKey || false,
          defaultValue: column.defaultValue,
          maxLength: column.maxLength,
          description: column.description,
          connectionId: 0, // 메인 DB 구분용
        }));

        // 디버깅: 매핑된 컬럼 정보 확인
        console.log(
          "🔍 매핑된 컬럼 정보 샘플:",
          mappedColumns.slice(0, 3).map((col) => ({
            columnName: col.columnName,
            inputType: col.inputType,
            webType: col.webType,
            connectionId: col.connectionId,
          }))
        );

        // status 컬럼 특별 확인
        const statusColumn = mappedColumns.find(
          (col) => col.columnName === "status"
        );
        if (statusColumn) {
          console.log("🔍 status 컬럼 상세 정보:", statusColumn);
        }

        return mappedColumns;
      }

      // 외부 DB 연결 정보 가져오기
      const connectionResult =
        await ExternalDbConnectionService.getConnectionById(connectionId);
      if (!connectionResult.success || !connectionResult.data) {
        throw new Error(`커넥션을 찾을 수 없습니다: ${connectionId}`);
      }
      const connection = connectionResult.data;

      // 외부 DB의 컬럼 정보 조회
      console.log(
        `🔍 외부 DB 컬럼 정보 조회 시작: connectionId=${connectionId}, table=${tableName}`
      );

      const columnsResult = await ExternalDbConnectionService.getTableColumns(
        connectionId,
        tableName
      );

      if (!columnsResult.success || !columnsResult.data) {
        console.error(`❌ 외부 DB 컬럼 조회 실패: ${columnsResult.message}`);
        throw new Error(columnsResult.message || "컬럼 조회 실패");
      }
      const columns = columnsResult.data;

      console.log(`✅ 외부 DB 컬럼 조회 성공: ${columns.length}개`);

      // MSSQL 컬럼 데이터 구조 디버깅
      if (columns.length > 0) {
        console.log(
          `🔍 MSSQL 컬럼 데이터 구조 분석:`,
          JSON.stringify(columns[0], null, 2)
        );
        console.log(`🔍 모든 컬럼 키들:`, Object.keys(columns[0]));
      }

      return columns.map((column: any) => {
        // MSSQL과 PostgreSQL 데이터 타입 필드명이 다를 수 있음
        // MSSQL: name, type, description (MSSQLConnector에서 alias로 지정)
        // PostgreSQL: column_name, data_type, column_comment
        const dataType =
          column.type || // MSSQL (MSSQLConnector alias)
          column.data_type || // PostgreSQL
          column.DATA_TYPE ||
          column.Type ||
          column.dataType ||
          column.column_type ||
          column.COLUMN_TYPE ||
          "unknown";
        const columnName =
          column.name || // MSSQL (MSSQLConnector alias)
          column.column_name || // PostgreSQL
          column.COLUMN_NAME ||
          column.Name ||
          column.columnName ||
          column.COLUMN_NAME;
        const columnComment =
          column.description || // MSSQL (MSSQLConnector alias)
          column.column_comment || // PostgreSQL
          column.COLUMN_COMMENT ||
          column.Description ||
          column.comment;

        console.log(`🔍 컬럼 매핑: ${columnName} - 타입: ${dataType}`);

        return {
          columnName: columnName,
          displayName: columnComment || columnName, // 라벨(comment)이 있으면 라벨 사용, 없으면 컬럼명
          dataType: dataType,
          dbType: dataType,
          webType: this.mapDataTypeToWebType(dataType),
          inputType: "direct", // 외부 DB는 항상 direct (코드 타입 없음)
          isNullable:
            column.nullable === "YES" || // MSSQL (MSSQLConnector alias)
            column.is_nullable === "YES" || // PostgreSQL
            column.IS_NULLABLE === "YES" ||
            column.Nullable === true,
          isPrimaryKey: column.is_primary_key || column.IS_PRIMARY_KEY || false,
          defaultValue:
            column.default_value || // MSSQL (MSSQLConnector alias)
            column.column_default || // PostgreSQL
            column.COLUMN_DEFAULT,
          maxLength:
            column.max_length || // MSSQL (MSSQLConnector alias)
            column.character_maximum_length || // PostgreSQL
            column.CHARACTER_MAXIMUM_LENGTH,
          connectionId: connectionId, // 외부 DB 구분용
          description: columnComment,
        };
      });
    } catch (error) {
      logger.error(`컬럼 정보 조회 실패: ${error}`);
      throw new Error(
        `컬럼 정보 조회 실패: ${error instanceof Error ? error.message : error}`
      );
    }
  }

  /**
   * 🆕 자기 자신 테이블 작업 전용 검증
   */
  async validateSelfTableOperation(
    tableName: string,
    operation: "update" | "delete",
    conditions: any[]
  ): Promise<ValidationResult> {
    try {
      logger.info(
        `자기 자신 테이블 작업 검증: table=${tableName}, operation=${operation}`
      );

      const warnings: string[] = [];

      // 1. 기본 조건 체크
      if (!conditions || conditions.length === 0) {
        return {
          isValid: false,
          error: `자기 자신 테이블 ${operation.toUpperCase()} 작업에는 반드시 조건이 필요합니다.`,
        };
      }

      // 2. DELETE 작업에 대한 추가 검증
      if (operation === "delete") {
        // 부정 조건 체크
        const hasNegativeConditions = conditions.some((condition) => {
          const conditionStr = JSON.stringify(condition).toLowerCase();
          return (
            conditionStr.includes("!=") ||
            conditionStr.includes("not in") ||
            conditionStr.includes("not exists")
          );
        });

        if (hasNegativeConditions) {
          return {
            isValid: false,
            error:
              "자기 자신 테이블 삭제 시 부정 조건(!=, NOT IN, NOT EXISTS)은 위험합니다.",
          };
        }

        // 조건 개수 체크
        if (conditions.length < 2) {
          warnings.push(
            "자기 자신 테이블 삭제 시 WHERE 조건을 2개 이상 설정하는 것을 권장합니다."
          );
        }
      }

      // 3. UPDATE 작업에 대한 추가 검증
      if (operation === "update") {
        warnings.push("자기 자신 테이블 업데이트 시 무한 루프에 주의하세요.");
      }

      return {
        isValid: true,
        warnings: warnings.length > 0 ? warnings : undefined,
      };
    } catch (error) {
      logger.error(`자기 자신 테이블 작업 검증 실패: ${error}`);
      return {
        isValid: false,
        error: `검증 과정에서 오류가 발생했습니다: ${error instanceof Error ? error.message : error}`,
      };
    }
  }

  /**
   * 🆕 메인 DB 작업 (connectionId = 0인 경우)
   */
  async executeOnMainDatabase(
    operation: "select" | "insert" | "update" | "delete",
    tableName: string,
    data?: Record<string, any>,
    conditions?: Record<string, any>
  ): Promise<any> {
    try {
      logger.info(
        `메인 DB 작업 실행: operation=${operation}, table=${tableName}`
      );

      switch (operation) {
        case "select":
          let sql = `SELECT * FROM ${tableName}`;
          const queryParams: any[] = [];

          if (conditions && Object.keys(conditions).length > 0) {
            const whereClause = Object.keys(conditions)
              .map((key, index) => `${key} = $${index + 1}`)
              .join(" AND ");
            sql += ` WHERE ${whereClause}`;
            queryParams.push(...Object.values(conditions));
          }

          return await query(sql, queryParams);

        case "insert":
          if (!data) throw new Error("INSERT 작업에는 데이터가 필요합니다.");

          const insertColumns = Object.keys(data);
          const insertValues = Object.values(data);
          const insertPlaceholders = insertValues
            .map((_, index) => `$${index + 1}`)
            .join(", ");

          const insertQuery = `
            INSERT INTO ${tableName} (${insertColumns.join(", ")})
            VALUES (${insertPlaceholders})
            RETURNING *
          `;

          const insertResult = await query(insertQuery, insertValues);
          return Array.isArray(insertResult) && insertResult.length > 0
            ? insertResult[0]
            : insertResult;

        case "update":
          if (!data) throw new Error("UPDATE 작업에는 데이터가 필요합니다.");
          if (!conditions)
            throw new Error("UPDATE 작업에는 조건이 필요합니다.");

          const setClause = Object.keys(data)
            .map((key, index) => `${key} = $${index + 1}`)
            .join(", ");

          const updateWhereClause = Object.keys(conditions)
            .map(
              (key, index) =>
                `${key} = $${Object.keys(data).length + index + 1}`
            )
            .join(" AND ");

          const updateQuery = `
            UPDATE ${tableName}
            SET ${setClause}
            WHERE ${updateWhereClause}
            RETURNING *
          `;

          const updateParams = [
            ...Object.values(data),
            ...Object.values(conditions),
          ];
          return await query(updateQuery, updateParams);

        case "delete":
          if (!conditions)
            throw new Error("DELETE 작업에는 조건이 필요합니다.");

          const deleteWhereClause = Object.keys(conditions)
            .map((key, index) => `${key} = $${index + 1}`)
            .join(" AND ");

          const deleteQuery = `
            DELETE FROM ${tableName}
            WHERE ${deleteWhereClause}
            RETURNING *
          `;

          return await query(deleteQuery, Object.values(conditions));

        default:
          throw new Error(`지원하지 않는 작업입니다: ${operation}`);
      }
    } catch (error) {
      logger.error(`메인 DB 작업 실패: ${error}`);
      throw new Error(
        `메인 DB 작업 실패: ${error instanceof Error ? error.message : error}`
      );
    }
  }

  /**
   * 데이터 타입을 웹 타입으로 매핑
   */
  private mapDataTypeToWebType(dataType: string | undefined | null): string {
    // 안전한 타입 검사
    if (!dataType || typeof dataType !== "string") {
      console.warn(`⚠️ 잘못된 데이터 타입: ${dataType}, 기본값 'text' 사용`);
      return "text";
    }

    const lowerType = dataType.toLowerCase();

    // PostgreSQL & MSSQL 타입 매핑
    if (
      lowerType.includes("int") ||
      lowerType.includes("serial") ||
      lowerType.includes("bigint")
    ) {
      return "number";
    }
    if (
      lowerType.includes("decimal") ||
      lowerType.includes("numeric") ||
      lowerType.includes("float") ||
      lowerType.includes("money") ||
      lowerType.includes("real")
    ) {
      return "decimal";
    }
    if (lowerType.includes("date") && !lowerType.includes("time")) {
      return "date";
    }
    if (
      lowerType.includes("timestamp") ||
      lowerType.includes("datetime") ||
      lowerType.includes("datetime2")
    ) {
      return "datetime";
    }
    if (lowerType.includes("bool") || lowerType.includes("bit")) {
      return "boolean";
    }
    if (
      lowerType.includes("text") ||
      lowerType.includes("clob") ||
      lowerType.includes("ntext")
    ) {
      return "textarea";
    }
    // MSSQL 특수 타입들
    if (
      lowerType.includes("varchar") ||
      lowerType.includes("nvarchar") ||
      lowerType.includes("char")
    ) {
      return "text";
    }

    return "text";
  }
}
