// 배치관리 컨트롤러
// 작성일: 2024-12-24

import { Request, Response } from "express";
import { BatchService } from "../services/batchService";
import { BatchSchedulerService } from "../services/batchSchedulerService";
import { BatchExternalDbService } from "../services/batchExternalDbService";
import {
  BatchConfigFilter,
  CreateBatchConfigRequest,
  UpdateBatchConfigRequest,
} from "../types/batchTypes";

export interface AuthenticatedRequest extends Request {
  user?: {
    userId: string;
    username: string;
    companyCode: string;
  };
}

export class BatchController {
  /**
   * 배치 설정 목록 조회 (회사별)
   * GET /api/batch-configs
   */
  static async getBatchConfigs(req: AuthenticatedRequest, res: Response) {
    try {
      const { page = 1, limit = 10, search, isActive } = req.query;
      const userCompanyCode = req.user?.companyCode;

      const filter: BatchConfigFilter = {
        page: Number(page),
        limit: Number(limit),
        search: search as string,
        is_active: isActive as string,
      };

      const result = await BatchService.getBatchConfigs(
        filter,
        userCompanyCode
      );

      res.json({
        success: true,
        data: result.data,
        pagination: result.pagination,
      });
    } catch (error) {
      console.error("배치 설정 목록 조회 오류:", error);
      res.status(500).json({
        success: false,
        message: "배치 설정 목록 조회에 실패했습니다.",
      });
    }
  }

  /**
   * 사용 가능한 커넥션 목록 조회
   * GET /api/batch-configs/connections
   */
  static async getAvailableConnections(
    req: AuthenticatedRequest,
    res: Response
  ) {
    try {
      const result = await BatchExternalDbService.getAvailableConnections();

      if (result.success) {
        res.json(result);
      } else {
        res.status(500).json(result);
      }
    } catch (error) {
      console.error("커넥션 목록 조회 오류:", error);
      res.status(500).json({
        success: false,
        message: "커넥션 목록 조회에 실패했습니다.",
      });
    }
  }

  /**
   * 테이블 목록 조회 (내부/외부 DB)
   * GET /api/batch-configs/connections/:type/tables
   * GET /api/batch-configs/connections/:type/:id/tables
   */
  static async getTablesFromConnection(
    req: AuthenticatedRequest,
    res: Response
  ) {
    try {
      const { type, id } = req.params;

      if (!type || (type !== "internal" && type !== "external")) {
        return res.status(400).json({
          success: false,
          message: "올바른 연결 타입을 지정해주세요. (internal 또는 external)",
        });
      }

      const connectionId = type === "external" ? Number(id) : undefined;
      const result = await BatchService.getTables(
        type as "internal" | "external",
        connectionId
      );

      if (result.success) {
        return res.json(result);
      } else {
        return res.status(500).json(result);
      }
    } catch (error) {
      console.error("테이블 목록 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "테이블 목록 조회에 실패했습니다.",
      });
    }
  }

  /**
   * 테이블 컬럼 정보 조회 (내부/외부 DB)
   * GET /api/batch-configs/connections/:type/tables/:tableName/columns
   * GET /api/batch-configs/connections/:type/:id/tables/:tableName/columns
   */
  static async getTableColumns(req: AuthenticatedRequest, res: Response) {
    try {
      const { type, id, tableName } = req.params;

      if (!type || !tableName) {
        return res.status(400).json({
          success: false,
          message: "연결 타입과 테이블명을 모두 지정해주세요.",
        });
      }

      if (type !== "internal" && type !== "external") {
        return res.status(400).json({
          success: false,
          message: "올바른 연결 타입을 지정해주세요. (internal 또는 external)",
        });
      }

      const connectionId = type === "external" ? Number(id) : undefined;
      const result = await BatchService.getColumns(
        tableName,
        type as "internal" | "external",
        connectionId
      );

      if (result.success) {
        return res.json(result);
      } else {
        return res.status(500).json(result);
      }
    } catch (error) {
      console.error("컬럼 정보 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "컬럼 정보 조회에 실패했습니다.",
      });
    }
  }

  /**
   * 특정 배치 설정 조회 (회사별)
   * GET /api/batch-configs/:id
   */
  static async getBatchConfigById(req: AuthenticatedRequest, res: Response) {
    try {
      const { id } = req.params;
      const result = await BatchService.getBatchConfigById(Number(id));

      if (!result.success || !result.data) {
        return res.status(404).json({
          success: false,
          message: result.message || "배치 설정을 찾을 수 없습니다.",
        });
      }

      return res.json({
        success: true,
        data: result.data,
      });
    } catch (error) {
      console.error("배치 설정 조회 오류:", error);
      return res.status(500).json({
        success: false,
        message: "배치 설정 조회에 실패했습니다.",
      });
    }
  }

  /**
   * 배치 설정 생성
   * POST /api/batch-configs
   */
  static async createBatchConfig(req: AuthenticatedRequest, res: Response) {
    try {
      const { batchName, description, cronSchedule, mappings } = req.body;

      if (
        !batchName ||
        !cronSchedule ||
        !mappings ||
        !Array.isArray(mappings)
      ) {
        return res.status(400).json({
          success: false,
          message:
            "필수 필드가 누락되었습니다. (batchName, cronSchedule, mappings)",
        });
      }

      const batchConfig = await BatchService.createBatchConfig({
        batchName,
        description,
        cronSchedule,
        mappings,
      } as CreateBatchConfigRequest);

      // 생성된 배치가 활성화 상태라면 스케줄러에 등록 (즉시 실행 비활성화)
      if (
        batchConfig.data &&
        batchConfig.data.is_active === "Y" &&
        batchConfig.data.id
      ) {
        await BatchSchedulerService.updateBatchSchedule(
          batchConfig.data.id,
          false
        );
      }

      return res.status(201).json({
        success: true,
        data: batchConfig,
        message: "배치 설정이 성공적으로 생성되었습니다.",
      });
    } catch (error) {
      console.error("배치 설정 생성 오류:", error);
      return res.status(500).json({
        success: false,
        message: "배치 설정 생성에 실패했습니다.",
      });
    }
  }

  /**
   * 배치 설정 수정 (회사별)
   * PUT /api/batch-configs/:id
   */
  static async updateBatchConfig(req: AuthenticatedRequest, res: Response) {
    try {
      const { id } = req.params;
      const { batchName, description, cronSchedule, mappings, isActive } =
        req.body;
      const userId = req.user?.userId;
      const userCompanyCode = req.user?.companyCode;

      if (!batchName || !cronSchedule) {
        return res.status(400).json({
          success: false,
          message: "필수 필드가 누락되었습니다. (batchName, cronSchedule)",
        });
      }

      const batchConfig = await BatchService.updateBatchConfig(
        Number(id),
        {
          batchName,
          description,
          cronSchedule,
          mappings,
          isActive,
        } as UpdateBatchConfigRequest,
        userId,
        userCompanyCode
      );

      if (!batchConfig) {
        return res.status(404).json({
          success: false,
          message: "배치 설정을 찾을 수 없습니다.",
        });
      }

      // 스케줄러에서 배치 스케줄 업데이트 (즉시 실행 비활성화)
      await BatchSchedulerService.updateBatchSchedule(Number(id), false);

      return res.json({
        success: true,
        data: batchConfig,
        message: "배치 설정이 성공적으로 수정되었습니다.",
      });
    } catch (error) {
      console.error("배치 설정 수정 오류:", error);
      return res.status(500).json({
        success: false,
        message: "배치 설정 수정에 실패했습니다.",
      });
    }
  }

  /**
   * 배치 설정 삭제 (논리 삭제, 회사별)
   * DELETE /api/batch-configs/:id
   */
  static async deleteBatchConfig(req: AuthenticatedRequest, res: Response) {
    try {
      const { id } = req.params;
      const userId = req.user?.userId;
      const userCompanyCode = req.user?.companyCode;
      const result = await BatchService.deleteBatchConfig(
        Number(id),
        userId,
        userCompanyCode
      );

      if (!result) {
        return res.status(404).json({
          success: false,
          message: "배치 설정을 찾을 수 없습니다.",
        });
      }

      return res.json({
        success: true,
        message: "배치 설정이 성공적으로 삭제되었습니다.",
      });
    } catch (error) {
      console.error("배치 설정 삭제 오류:", error);
      return res.status(500).json({
        success: false,
        message: "배치 설정 삭제에 실패했습니다.",
      });
    }
  }
}
