/**
 * DDL 실행 컨트롤러
 * 테이블/컬럼 생성 API 엔드포인트
 */

import { Response } from "express";
import { AuthenticatedRequest } from "../middleware/superAdminMiddleware";
import { DDLExecutionService } from "../services/ddlExecutionService";
import { DDLAuditLogger } from "../services/ddlAuditLogger";
import { CreateTableRequest, AddColumnRequest } from "../types/ddl";
import { logger } from "../utils/logger";
import { auditLogService, getClientIp } from "../services/auditLogService";

export class DDLController {
  /**
   * POST /api/ddl/tables - 새 테이블 생성
   */
  static async createTable(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { tableName, columns, description }: CreateTableRequest = req.body;
      const userId = req.user!.userId;
      const userCompanyCode = req.user!.companyCode;

      // 입력값 기본 검증
      if (!tableName || !columns || columns.length === 0) {
        res.status(400).json({
          success: false,
          error: {
            code: "INVALID_INPUT",
            details: "테이블명과 최소 1개의 컬럼이 필요합니다.",
          },
        });
        return;
      }

      logger.info("테이블 생성 요청", {
        tableName,
        userId,
        columnCount: columns.length,
        ip: req.ip,
      });

      // inputType을 webType으로 변환 (레거시 호환성)
      const processedColumns = columns.map((col) => ({
        ...col,
        webType: (col.inputType || col.webType || "text") as any,
      }));

      // DDL 실행 서비스 호출
      const ddlService = new DDLExecutionService();
      const result = await ddlService.createTable(
        tableName,
        processedColumns,
        userCompanyCode,
        userId,
        description
      );

      if (result.success) {
        auditLogService.log({
          companyCode: userCompanyCode || "",
          userId,
          action: "CREATE",
          resourceType: "TABLE",
          resourceId: tableName,
          resourceName: tableName,
          tableName,
          summary: `테이블 "${tableName}" 생성 (${columns.length}개 컬럼)`,
          changes: { after: { tableName, columnCount: columns.length, description } },
          ipAddress: getClientIp(req),
          requestPath: req.originalUrl,
        });

        res.status(200).json({
          success: true,
          message: result.message,
          data: {
            tableName,
            columnCount: columns.length,
            executedQuery: result.executedQuery,
          },
        });
      } else {
        res.status(400).json({
          success: false,
          message: result.message,
          error: result.error,
        });
      }
    } catch (error) {
      logger.error("테이블 생성 컨트롤러 오류:", {
        error: (error as Error).message,
        stack: (error as Error).stack,
        userId: req.user?.userId,
        body: req.body,
      });

      res.status(500).json({
        success: false,
        error: {
          code: "INTERNAL_SERVER_ERROR",
          details: "테이블 생성 중 서버 오류가 발생했습니다.",
        },
      });
    }
  }

  /**
   * POST /api/ddl/tables/:tableName/columns - 컬럼 추가
   */
  static async addColumn(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { tableName } = req.params;
      const { column }: AddColumnRequest = req.body;
      const userId = req.user!.userId;
      const userCompanyCode = req.user!.companyCode;

      // 입력값 기본 검증
      if (!tableName) {
        res.status(400).json({
          success: false,
          error: {
            code: "INVALID_INPUT",
            details: "테이블명이 필요합니다.",
          },
        });
        return;
      }

      if (!column || !column.name || (!column.inputType && !column.webType)) {
        res.status(400).json({
          success: false,
          error: {
            code: "INVALID_INPUT",
            details: "컬럼명과 입력타입이 필요합니다.",
          },
        });
        return;
      }

      logger.info("컬럼 추가 요청", {
        tableName,
        columnName: column.name,
        webType: column.webType,
        userId,
        ip: req.ip,
      });

      // inputType을 webType으로 변환 (레거시 호환성)
      const processedColumn = {
        ...column,
        webType: (column.inputType || column.webType || "text") as any,
      };

      // DDL 실행 서비스 호출
      const ddlService = new DDLExecutionService();
      const result = await ddlService.addColumn(
        tableName,
        processedColumn,
        userCompanyCode,
        userId
      );

      if (result.success) {
        res.status(200).json({
          success: true,
          message: result.message,
          data: {
            tableName,
            columnName: column.name,
            webType: column.webType,
            executedQuery: result.executedQuery,
          },
        });
      } else {
        res.status(400).json({
          success: false,
          message: result.message,
          error: result.error,
        });
      }
    } catch (error) {
      logger.error("컬럼 추가 컨트롤러 오류:", {
        error: (error as Error).message,
        stack: (error as Error).stack,
        userId: req.user?.userId,
        tableName: req.params.tableName,
        body: req.body,
      });

      res.status(500).json({
        success: false,
        error: {
          code: "INTERNAL_SERVER_ERROR",
          details: "컬럼 추가 중 서버 오류가 발생했습니다.",
        },
      });
    }
  }

  /**
   * GET /api/ddl/logs - DDL 실행 로그 조회
   */
  static async getDDLLogs(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { limit, userId, ddlType } = req.query;

      const logs = await DDLAuditLogger.getRecentDDLLogs(
        limit ? parseInt(limit as string) : 50,
        userId as string,
        ddlType as string
      );

      res.json({
        success: true,
        data: {
          logs,
          total: logs.length,
        },
      });
    } catch (error) {
      logger.error("DDL 로그 조회 오류:", error);

      res.status(500).json({
        success: false,
        error: {
          code: "LOG_RETRIEVAL_FAILED",
          details: "DDL 로그 조회 중 오류가 발생했습니다.",
        },
      });
    }
  }

  /**
   * GET /api/ddl/statistics - DDL 실행 통계 조회
   */
  static async getDDLStatistics(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { fromDate, toDate } = req.query;

      const statistics = await DDLAuditLogger.getDDLStatistics(
        fromDate ? new Date(fromDate as string) : undefined,
        toDate ? new Date(toDate as string) : undefined
      );

      res.json({
        success: true,
        data: statistics,
      });
    } catch (error) {
      logger.error("DDL 통계 조회 오류:", error);

      res.status(500).json({
        success: false,
        error: {
          code: "STATISTICS_RETRIEVAL_FAILED",
          details: "DDL 통계 조회 중 오류가 발생했습니다.",
        },
      });
    }
  }

  /**
   * GET /api/ddl/tables/:tableName/info - 생성된 테이블 정보 조회
   */
  static async getTableInfo(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { tableName } = req.params;

      const ddlService = new DDLExecutionService();
      const tableInfo = await ddlService.getCreatedTableInfo(tableName);

      if (!tableInfo) {
        res.status(404).json({
          success: false,
          error: {
            code: "TABLE_NOT_FOUND",
            details: `테이블 '${tableName}'을 찾을 수 없습니다.`,
          },
        });
        return;
      }

      res.json({
        success: true,
        data: tableInfo,
      });
    } catch (error) {
      logger.error("테이블 정보 조회 오류:", error);

      res.status(500).json({
        success: false,
        error: {
          code: "TABLE_INFO_RETRIEVAL_FAILED",
          details: "테이블 정보 조회 중 오류가 발생했습니다.",
        },
      });
    }
  }

  /**
   * GET /api/ddl/tables/:tableName/history - 테이블 DDL 히스토리 조회
   */
  static async getTableDDLHistory(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { tableName } = req.params;

      const history = await DDLAuditLogger.getTableDDLHistory(tableName);

      res.json({
        success: true,
        data: {
          tableName,
          history,
          total: history.length,
        },
      });
    } catch (error) {
      logger.error("테이블 DDL 히스토리 조회 오류:", error);

      res.status(500).json({
        success: false,
        error: {
          code: "HISTORY_RETRIEVAL_FAILED",
          details: "테이블 DDL 히스토리 조회 중 오류가 발생했습니다.",
        },
      });
    }
  }

  /**
   * POST /api/ddl/validate/table - 테이블 생성 사전 검증
   */
  static async validateTableCreation(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { tableName, columns }: CreateTableRequest = req.body;

      if (!tableName || !columns) {
        res.status(400).json({
          success: false,
          error: {
            code: "INVALID_INPUT",
            details: "테이블명과 컬럼 정보가 필요합니다.",
          },
        });
        return;
      }

      // 검증만 수행 (실제 생성하지 않음)
      const { DDLSafetyValidator } = await import(
        "../services/ddlSafetyValidator"
      );
      const validationReport = DDLSafetyValidator.generateValidationReport(
        tableName,
        columns
      );

      res.json({
        success: true,
        data: {
          isValid: validationReport.validationResult.isValid,
          errors: validationReport.validationResult.errors,
          warnings: validationReport.validationResult.warnings,
          summary: validationReport.summary,
        },
      });
    } catch (error) {
      logger.error("테이블 생성 검증 오류:", error);

      res.status(500).json({
        success: false,
        error: {
          code: "VALIDATION_ERROR",
          details: "테이블 생성 검증 중 오류가 발생했습니다.",
        },
      });
    }
  }

  /**
   * DELETE /api/ddl/tables/:tableName - 테이블 삭제 (최고 관리자 전용)
   */
  static async dropTable(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { tableName } = req.params;
      const userId = req.user!.userId;
      const userCompanyCode = req.user!.companyCode;

      // 입력값 기본 검증
      if (!tableName) {
        res.status(400).json({
          success: false,
          error: {
            code: "INVALID_INPUT",
            details: "테이블명이 필요합니다.",
          },
        });
        return;
      }

      logger.info("테이블 삭제 요청", {
        tableName,
        userId,
        userCompanyCode,
        ip: req.ip,
      });

      // DDL 실행 서비스 호출
      const ddlService = new DDLExecutionService();
      const result = await ddlService.dropTable(
        tableName,
        userCompanyCode,
        userId
      );

      if (result.success) {
        auditLogService.log({
          companyCode: userCompanyCode || "",
          userId,
          action: "DELETE",
          resourceType: "TABLE",
          resourceId: tableName,
          resourceName: tableName,
          tableName,
          summary: `테이블 "${tableName}" 삭제`,
          ipAddress: getClientIp(req as any),
          requestPath: req.originalUrl,
        });

        res.status(200).json({
          success: true,
          message: result.message,
          data: {
            tableName,
            executedQuery: result.executedQuery,
          },
        });
      } else {
        res.status(400).json({
          success: false,
          message: result.message,
          error: result.error,
        });
      }
    } catch (error) {
      logger.error("테이블 삭제 컨트롤러 오류:", {
        error: (error as Error).message,
        stack: (error as Error).stack,
        userId: req.user?.userId,
        tableName: req.params.tableName,
      });

      res.status(500).json({
        success: false,
        error: {
          code: "INTERNAL_SERVER_ERROR",
          details: "테이블 삭제 중 서버 오류가 발생했습니다.",
        },
      });
    }
  }

  /**
   * DELETE /api/ddl/logs/cleanup - 오래된 DDL 로그 정리
   */
  static async cleanupOldLogs(
    req: AuthenticatedRequest,
    res: Response
  ): Promise<void> {
    try {
      const { retentionDays } = req.query;
      const days = retentionDays ? parseInt(retentionDays as string) : 90;

      const deletedCount = await DDLAuditLogger.cleanupOldLogs(days);

      res.json({
        success: true,
        message: `${deletedCount}개의 오래된 DDL 로그가 삭제되었습니다.`,
        data: {
          deletedCount,
          retentionDays: days,
        },
      });
    } catch (error) {
      logger.error("DDL 로그 정리 오류:", error);

      res.status(500).json({
        success: false,
        error: {
          code: "LOG_CLEANUP_FAILED",
          details: "DDL 로그 정리 중 오류가 발생했습니다.",
        },
      });
    }
  }
}
