import { logger } from "../utils/logger";
import { query } from "../database/db";
import { ExternalDbConnectionService } from "./externalDbConnectionService";

interface MapDataQuery {
  connectionId?: number;
  tableName: string;
  latColumn: string;
  lngColumn: string;
  labelColumn?: string;
  statusColumn?: string;
  additionalColumns?: string[];
  whereClause?: string;
}

export interface MapMarker {
  id: string | number;
  latitude: number;
  longitude: number;
  label?: string;
  status?: string;
  additionalInfo?: Record<string, any>;
}

/**
 * 지도 데이터 서비스
 * 외부/내부 DB에서 위도/경도 데이터를 조회하여 지도 마커로 변환
 */
export class MapDataService {
  constructor() {
    // ExternalDbConnectionService는 static 메서드를 사용
  }

  /**
   * 외부 DB에서 지도 데이터 조회
   */
  async getMapData(params: MapDataQuery): Promise<MapMarker[]> {
    try {
      logger.info("🗺️ 외부 DB 지도 데이터 조회 시작:", params);

      // SELECT할 컬럼 목록 구성
      const selectColumns = [
        params.latColumn,
        params.lngColumn,
        params.labelColumn,
        params.statusColumn,
        ...(params.additionalColumns || []),
      ].filter(Boolean);

      // 중복 제거
      const uniqueColumns = Array.from(new Set(selectColumns));

      // SQL 쿼리 구성
      let sql = `SELECT ${uniqueColumns.map((col) => `"${col}"`).join(", ")} FROM "${params.tableName}"`;

      if (params.whereClause) {
        sql += ` WHERE ${params.whereClause}`;
      }

      logger.info("📝 실행할 SQL:", sql);

      // 외부 DB 쿼리 실행 (static 메서드 사용)
      const result = await ExternalDbConnectionService.executeQuery(
        params.connectionId!,
        sql
      );

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

      // 데이터를 MapMarker 형식으로 변환
      const markers = this.convertToMarkers(
        result.data,
        params.latColumn,
        params.lngColumn,
        params.labelColumn,
        params.statusColumn,
        params.additionalColumns
      );

      logger.info(`✅ ${markers.length}개의 마커 데이터 변환 완료`);

      return markers;
    } catch (error) {
      logger.error("❌ 외부 DB 지도 데이터 조회 오류:", error);
      throw error;
    }
  }

  /**
   * 내부 DB에서 지도 데이터 조회
   */
  async getInternalMapData(
    params: Omit<MapDataQuery, "connectionId">
  ): Promise<MapMarker[]> {
    try {
      logger.info("🗺️ 내부 DB 지도 데이터 조회 시작:", params);

      // SELECT할 컬럼 목록 구성
      const selectColumns = [
        params.latColumn,
        params.lngColumn,
        params.labelColumn,
        params.statusColumn,
        ...(params.additionalColumns || []),
      ].filter(Boolean);

      // 중복 제거
      const uniqueColumns = Array.from(new Set(selectColumns));

      // SQL 쿼리 구성
      let sql = `SELECT ${uniqueColumns.map((col) => `"${col}"`).join(", ")} FROM "${params.tableName}"`;

      if (params.whereClause) {
        sql += ` WHERE ${params.whereClause}`;
      }

      logger.info("📝 실행할 SQL:", sql);

      // 내부 DB 쿼리 실행
      const rows = await query(sql);

      // 데이터를 MapMarker 형식으로 변환
      const markers = this.convertToMarkers(
        rows,
        params.latColumn,
        params.lngColumn,
        params.labelColumn,
        params.statusColumn,
        params.additionalColumns
      );

      logger.info(`✅ ${markers.length}개의 마커 데이터 변환 완료`);

      return markers;
    } catch (error) {
      logger.error("❌ 내부 DB 지도 데이터 조회 오류:", error);
      throw error;
    }
  }

  /**
   * DB 결과를 MapMarker 배열로 변환
   */
  private convertToMarkers(
    data: any[],
    latColumn: string,
    lngColumn: string,
    labelColumn?: string,
    statusColumn?: string,
    additionalColumns?: string[]
  ): MapMarker[] {
    const markers: MapMarker[] = [];

    for (let i = 0; i < data.length; i++) {
      const row = data[i];

      // 위도/경도 추출 (다양한 컬럼명 지원)
      const lat = this.extractCoordinate(row, latColumn);
      const lng = this.extractCoordinate(row, lngColumn);

      // 유효한 좌표인지 확인
      if (lat === null || lng === null || isNaN(lat) || isNaN(lng)) {
        logger.warn(`⚠️ 유효하지 않은 좌표 스킵: row ${i}`, { lat, lng });
        continue;
      }

      // 위도 범위 체크 (-90 ~ 90)
      if (lat < -90 || lat > 90) {
        logger.warn(`⚠️ 위도 범위 초과: ${lat}`);
        continue;
      }

      // 경도 범위 체크 (-180 ~ 180)
      if (lng < -180 || lng > 180) {
        logger.warn(`⚠️ 경도 범위 초과: ${lng}`);
        continue;
      }

      // 추가 정보 수집
      const additionalInfo: Record<string, any> = {};
      if (additionalColumns) {
        for (const col of additionalColumns) {
          if (col && row[col] !== undefined) {
            additionalInfo[col] = row[col];
          }
        }
      }

      // 마커 생성
      markers.push({
        id: row.id || row.ID || `marker-${i}`,
        latitude: lat,
        longitude: lng,
        label: labelColumn ? row[labelColumn] : undefined,
        status: statusColumn ? row[statusColumn] : undefined,
        additionalInfo: Object.keys(additionalInfo).length > 0 ? additionalInfo : undefined,
      });
    }

    return markers;
  }

  /**
   * 다양한 형식의 좌표 추출
   */
  private extractCoordinate(row: any, columnName: string): number | null {
    const value = row[columnName];

    if (value === null || value === undefined) {
      return null;
    }

    // 이미 숫자인 경우
    if (typeof value === "number") {
      return value;
    }

    // 문자열인 경우 파싱
    if (typeof value === "string") {
      const parsed = parseFloat(value);
      return isNaN(parsed) ? null : parsed;
    }

    return null;
  }
}

