// 외부 DB 연결 API 라우트
// 작성일: 2024-12-17

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

const router = Router();

/**
 * GET /api/external-db-connections
 * 외부 DB 연결 목록 조회
 */
/**
 * GET /api/external-db-connections/types/supported
 * 지원하는 DB 타입 목록 조회
 */
router.get(
  "/types/supported",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const { DB_TYPE_OPTIONS, DB_TYPE_DEFAULTS } = await import(
        "../types/externalDbTypes"
      );

      return res.status(200).json({
        success: true,
        data: {
          types: DB_TYPE_OPTIONS,
          defaults: DB_TYPE_DEFAULTS,
        },
        message: "지원하는 DB 타입 목록을 조회했습니다.",
      });
    } catch (error) {
      console.error("DB 타입 목록 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

router.get(
  "/",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const userCompanyCode = req.user?.companyCode;

      // 슈퍼 관리자는 쿼리 파라미터로 회사 지정 가능, 일반/회사 관리자는 자신의 회사만
      let companyCodeFilter: string | undefined;
      if (userCompanyCode === "*") {
        // 슈퍼 관리자: 쿼리 파라미터 사용 또는 전체
        companyCodeFilter = req.query.company_code as string;
      } else {
        // 회사 관리자/일반 사용자: 강제로 자신의 회사 코드 적용
        companyCodeFilter = userCompanyCode;
      }

      const filter: ExternalDbConnectionFilter = {
        db_type: req.query.db_type as string,
        is_active: req.query.is_active as string,
        company_code: companyCodeFilter,
        search: req.query.search as string,
      };

      // 빈 값 제거
      Object.keys(filter).forEach((key) => {
        if (!filter[key as keyof ExternalDbConnectionFilter]) {
          delete filter[key as keyof ExternalDbConnectionFilter];
        }
      });

      logger.info("외부 DB 연결 목록 조회", {
        userId: req.user?.userId,
        userCompanyCode,
        filterCompanyCode: companyCodeFilter,
        filter,
      });

      const result = await ExternalDbConnectionService.getConnections(
        filter,
        userCompanyCode
      );

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

/**
 * GET /api/external-db-connections/pool-status
 * 연결 풀 상태 조회
 */
router.get(
  "/pool-status",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const { ExternalDbConnectionPoolService } = await import(
        "../services/externalDbConnectionPoolService"
      );
      const poolService = ExternalDbConnectionPoolService.getInstance();
      const poolsStatus = poolService.getPoolsStatus();

      return res.status(200).json({
        success: true,
        data: {
          totalPools: poolsStatus.length,
          activePools: poolsStatus.filter((p) => p.activeConnections > 0)
            .length,
          pools: poolsStatus,
        },
        message: `${poolsStatus.length}개의 연결 풀 상태를 조회했습니다.`,
      });
    } catch (error) {
      console.error("연결 풀 상태 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * GET /api/external-db-connections/grouped
 * DB 타입별로 그룹화된 외부 DB 연결 목록 조회
 */
router.get(
  "/grouped",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const filter: ExternalDbConnectionFilter = {
        db_type: req.query.db_type as string,
        is_active: req.query.is_active as string,
        company_code: req.query.company_code as string,
        search: req.query.search as string,
      };

      // 빈 값 제거
      Object.keys(filter).forEach((key) => {
        if (!filter[key as keyof ExternalDbConnectionFilter]) {
          delete filter[key as keyof ExternalDbConnectionFilter];
        }
      });

      const result =
        await ExternalDbConnectionService.getConnectionsGroupedByType(filter);

      if (result.success) {
        return res.status(200).json(result);
      } else {
        return res.status(400).json(result);
      }
    } catch (error) {
      console.error("그룹화된 외부 DB 연결 목록 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "그룹화된 연결 목록 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * GET /api/external-db-connections/:id
 * 특정 외부 DB 연결 조회
 */
router.get(
  "/:id",
  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입니다.",
        });
      }

      const result = await ExternalDbConnectionService.getConnectionById(id);

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

/**
 * POST /api/external-db-connections
 * 새 외부 DB 연결 생성
 */
router.post(
  "/",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const connectionData: ExternalDbConnection = req.body;

      // 사용자 정보 추가
      if (req.user) {
        connectionData.created_by = req.user.userId;
        connectionData.updated_by = req.user.userId;
      }

      const result =
        await ExternalDbConnectionService.createConnection(connectionData);

      if (result.success) {
        return res.status(201).json(result);
      } else {
        return res.status(400).json(result);
      }
    } catch (error) {
      console.error("외부 DB 연결 생성 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * PUT /api/external-db-connections/:id
 * 외부 DB 연결 수정
 */
router.put(
  "/:id",
  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입니다.",
        });
      }

      const updateData: Partial<ExternalDbConnection> = req.body;

      // 사용자 정보 추가
      if (req.user) {
        updateData.updated_by = req.user.userId;
      }

      const result = await ExternalDbConnectionService.updateConnection(
        id,
        updateData
      );

      if (result.success) {
        return res.status(200).json(result);
      } else {
        return res.status(400).json(result);
      }
    } catch (error) {
      console.error("외부 DB 연결 수정 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * DELETE /api/external-db-connections/:id
 * 외부 DB 연결 삭제 (물리 삭제)
 */
router.delete(
  "/:id",
  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입니다.",
        });
      }

      const userCompanyCode = req.user?.companyCode;

      const result = await ExternalDbConnectionService.deleteConnection(
        id,
        userCompanyCode
      );

      if (result.success) {
        return res.status(200).json(result);
      } else {
        return res.status(404).json(result);
      }
    } catch (error) {
      console.error("외부 DB 연결 삭제 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * POST /api/external-db-connections/:id/test
 * 데이터베이스 연결 테스트 (ID 기반)
 */
router.post(
  "/:id/test",
  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입니다.",
          error: {
            code: "INVALID_ID",
            details: "연결 ID는 숫자여야 합니다.",
          },
        });
      }

      // 테스트용 비밀번호가 제공된 경우 사용
      const testData = req.body.password
        ? { password: req.body.password }
        : undefined;
      console.log(
        `🔍 [API] 연결테스트 요청 - ID: ${id}, 비밀번호 제공됨: ${!!req.body.password}`
      );

      const result = await ExternalDbConnectionService.testConnectionById(
        id,
        testData
      );

      return res.status(200).json({
        success: result.success,
        data: result,
        message: result.message,
      });
    } catch (error) {
      console.error("연결 테스트 오류:", error);
      return res.status(500).json({
        success: false,
        message: "연결 테스트 중 서버 오류가 발생했습니다.",
        error: {
          code: "SERVER_ERROR",
          details: error instanceof Error ? error.message : "알 수 없는 오류",
        },
      });
    }
  }
);

/**
 * POST /api/external-db-connections/:id/execute
 * SQL 쿼리 실행
 */
router.post(
  "/:id/execute",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const id = parseInt(req.params.id);
      const { query } = req.body;

      if (!query?.trim()) {
        return res.status(400).json({
          success: false,
          message: "쿼리가 입력되지 않았습니다.",
        });
      }

      const result = await ExternalDbConnectionService.executeQuery(id, query);
      return res.json(result);
    } catch (error) {
      console.error("쿼리 실행 오류:", error);
      return res.status(500).json({
        success: false,
        message: "쿼리 실행 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * GET /api/external-db-connections/:id/tables
 * 데이터베이스 테이블 목록 조회
 */
router.get(
  "/:id/tables",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      const id = parseInt(req.params.id);
      const result = await ExternalDbConnectionService.getTables(id);
      return res.json(result);
    } catch (error) {
      console.error("테이블 목록 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "테이블 목록 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

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

      if (!tableName) {
        return res.status(400).json({
          success: false,
          message: "테이블명이 입력되지 않았습니다.",
        });
      }

      const result = await ExternalDbConnectionService.getTableColumns(
        id,
        tableName
      );
      return res.json(result);
    } catch (error) {
      console.error("테이블 컬럼 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "테이블 컬럼 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

/**
 * 🆕 GET /api/external-db-connections/active
 * 제어관리용 활성 커넥션 목록 조회 (현재 DB 포함)
 */
router.get(
  "/control/active",
  authenticateToken,
  async (req: AuthenticatedRequest, res: Response) => {
    try {
      // 로그인한 사용자의 회사 코드 가져오기
      const userCompanyCode = req.user?.companyCode;

      // 슈퍼 관리자는 쿼리 파라미터로 지정한 회사 또는 전체(*) 조회 가능
      // 일반 사용자/회사 관리자는 자신의 회사만 조회 가능
      let companyCodeFilter: string;
      if (userCompanyCode === "*") {
        // 슈퍼 관리자
        companyCodeFilter = (req.query.company_code as string) || "*";
      } else {
        // 회사 관리자 또는 일반 사용자
        companyCodeFilter = userCompanyCode || "*";
      }

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

      logger.info("제어관리용 활성 커넥션 조회", {
        userId: req.user?.userId,
        userCompanyCode,
        filterCompanyCode: companyCodeFilter,
      });

      const externalConnections =
        await ExternalDbConnectionService.getConnections(
          filter,
          userCompanyCode
        );

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

      // 외부 커넥션들에 대해 연결 테스트 수행 (병렬 처리, 타임아웃 5초)
      const testedConnections = await Promise.all(
        (externalConnections.data || []).map(async (connection) => {
          try {
            // 개별 연결 테스트에 5초 타임아웃 적용
            const testPromise = ExternalDbConnectionService.testConnectionById(
              connection.id!
            );
            const timeoutPromise = new Promise<any>((_, reject) => {
              setTimeout(() => reject(new Error("연결 테스트 타임아웃")), 5000);
            });

            const testResult = await Promise.race([
              testPromise,
              timeoutPromise,
            ]);
            return testResult.success ? connection : null;
          } catch (error) {
            console.warn(
              `커넥션 테스트 실패 (ID: ${connection.id}):`,
              error instanceof Error ? error.message : error
            );
            return null;
          }
        })
      );

      // 테스트에 성공한 커넥션만 필터링
      const validExternalConnections = testedConnections.filter(
        (conn) => conn !== null
      );

      // 현재 메인 DB를 첫 번째로 추가
      const mainDbConnection = {
        id: 0,
        connection_name: "메인 데이터베이스 (현재 시스템)",
        description: "현재 시스템의 PostgreSQL 데이터베이스",
        db_type: "postgresql",
        host: "localhost",
        port: 5432,
        database_name: process.env.DB_NAME || "erp_database",
        username: "system",
        password: "***",
        is_active: "Y",
        company_code: "*",
        created_date: new Date(),
        updated_date: new Date(),
      };

      const allConnections = [mainDbConnection, ...validExternalConnections];

      return res.status(200).json({
        success: true,
        data: allConnections,
        message: "제어관리용 활성 커넥션 목록을 조회했습니다.",
      });
    } catch (error) {
      console.error("제어관리용 활성 커넥션 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "서버 내부 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "알 수 없는 오류",
      });
    }
  }
);

export default router;
