import { Router, Request, Response } from "express";
import {
  authenticateToken,
  AuthenticatedRequest,
} from "../../middleware/authMiddleware";
import { ExternalDbConnectionService } from "../../services/externalDbConnectionService";
import { ExternalDbConnectionFilter } from "../../types/externalDbTypes";
import logger from "../../utils/logger";

const router = Router();

/**
 * GET /api/dataflow/node-external-connections/tested
 * 노드 플로우용: 테스트에 성공한 외부 DB 커넥션 목록 조회
 */
router.get(
  "/tested",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      logger.info("🔍 노드 플로우용 테스트 완료된 커넥션 조회 요청");

      // 활성 상태의 외부 커넥션 조회
      const filter: ExternalDbConnectionFilter = {
        is_active: "Y",
      };

      const externalConnections =
        await ExternalDbConnectionService.getConnections(filter);

      if (!externalConnections.success) {
        return res.status(400).json(externalConnections);
      }

      // 외부 커넥션들에 대해 연결 테스트 수행 (제한된 병렬 처리 + 타임아웃 관리)
      const validExternalConnections: any[] = [];
      const connections = externalConnections.data || [];
      const MAX_CONCURRENT = 3; // 최대 동시 연결 수
      const TIMEOUT_MS = 3000; // 타임아웃 3초

      // 청크 단위로 처리 (최대 3개씩)
      for (let i = 0; i < connections.length; i += MAX_CONCURRENT) {
        const chunk = connections.slice(i, i + MAX_CONCURRENT);

        const chunkResults = await Promise.allSettled(
          chunk.map(async (connection) => {
            let testPromise: Promise<any> | null = null;
            let timeoutId: NodeJS.Timeout | null = null;

            try {
              // 타임아웃과 함께 테스트 실행
              testPromise = ExternalDbConnectionService.testConnectionById(
                connection.id!
              );

              const timeoutPromise = new Promise<never>((_, reject) => {
                timeoutId = setTimeout(() => {
                  reject(new Error("연결 테스트 타임아웃"));
                }, TIMEOUT_MS);
              });

              const testResult = await Promise.race([
                testPromise,
                timeoutPromise,
              ]);

              // 타임아웃 정리
              if (timeoutId) clearTimeout(timeoutId);

              if (testResult.success) {
                return {
                  id: connection.id,
                  connection_name: connection.connection_name,
                  description: connection.description,
                  db_type: connection.db_type,
                  host: connection.host,
                  port: connection.port,
                  database_name: connection.database_name,
                };
              }
              return null;
            } catch (error) {
              // 타임아웃 정리
              if (timeoutId) clearTimeout(timeoutId);

              // 🔥 타임아웃 시 연결 강제 해제
              try {
                const { DatabaseConnectorFactory } = await import(
                  "../../database/DatabaseConnectorFactory"
                );
                await DatabaseConnectorFactory.closeConnector(
                  connection.id!,
                  connection.db_type
                );
                logger.info(
                  `🧹 타임아웃/실패로 인한 커넥션 정리 완료: ${connection.connection_name}`
                );
              } catch (cleanupError) {
                logger.warn(
                  `커넥션 정리 실패 (ID: ${connection.id}):`,
                  cleanupError instanceof Error
                    ? cleanupError.message
                    : cleanupError
                );
              }

              logger.warn(
                `커넥션 테스트 실패 (ID: ${connection.id}):`,
                error instanceof Error ? error.message : error
              );
              return null;
            }
          })
        );

        // fulfilled 결과만 수집
        chunkResults.forEach((result) => {
          if (result.status === "fulfilled" && result.value !== null) {
            validExternalConnections.push(result.value);
          }
        });

        // 다음 청크 처리 전 짧은 대기 (연결 풀 안정화)
        if (i + MAX_CONCURRENT < connections.length) {
          await new Promise((resolve) => setTimeout(resolve, 100));
        }
      }

      logger.info(
        `✅ 테스트 성공한 커넥션: ${validExternalConnections.length}/${externalConnections.data?.length || 0}개`
      );

      return res.status(200).json({
        success: true,
        data: validExternalConnections,
        message: `테스트에 성공한 ${validExternalConnections.length}개의 커넥션을 조회했습니다.`,
      });
    } catch (error) {
      logger.error("노드 플로우용 커넥션 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * GET /api/dataflow/node-external-connections/:id/tables
 * 특정 외부 DB의 테이블 목록 조회
 */
router.get(
  "/:id/tables",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const id = parseInt(req.params.id);

      if (isNaN(id)) {
        return res.status(400).json({
          success: false,
          message: "유효하지 않은 연결 ID입니다.",
        });
      }

      logger.info(`🔍 외부 DB 테이블 목록 조회: connectionId=${id}`);

      const result =
        await ExternalDbConnectionService.getTablesFromConnection(id);

      return res.status(200).json(result);
    } catch (error) {
      logger.error("외부 DB 테이블 목록 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * GET /api/dataflow/node-external-connections/:id/tables/:tableName/columns
 * 특정 외부 DB 테이블의 컬럼 목록 조회
 */
router.get(
  "/:id/tables/:tableName/columns",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const id = parseInt(req.params.id);
      const { tableName } = req.params;

      if (isNaN(id)) {
        return res.status(400).json({
          success: false,
          message: "유효하지 않은 연결 ID입니다.",
        });
      }

      if (!tableName) {
        return res.status(400).json({
          success: false,
          message: "테이블명이 필요합니다.",
        });
      }

      logger.info(
        `🔍 외부 DB 컬럼 목록 조회: connectionId=${id}, table=${tableName}`
      );

      const result = await ExternalDbConnectionService.getColumnsFromConnection(
        id,
        tableName
      );

      return res.status(200).json(result);
    } catch (error) {
      logger.error("외부 DB 컬럼 목록 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

export default router;
