/**
 * 테이블 이력 조회 컨트롤러
 * 테이블 타입 관리의 {테이블명}_log 테이블과 연동
 */

import { Request, Response } from "express";
import { query } from "../database/db";
import { logger } from "../utils/logger";

export class TableHistoryController {
  /**
   * 특정 레코드의 변경 이력 조회
   */
  static async getRecordHistory(req: Request, res: Response): Promise<void> {
    try {
      const { tableName, recordId } = req.params;
      const { limit = 50, offset = 0, operationType, changedBy, startDate, endDate } = req.query;

      logger.info(`📜 테이블 이력 조회 요청:`, {
        tableName,
        recordId,
        limit,
        offset,
      });

      // 로그 테이블명 생성
      const logTableName = `${tableName}_log`;

      // 동적 WHERE 조건 생성
      const whereConditions: string[] = [`original_id = $1`];
      const queryParams: any[] = [recordId];
      let paramIndex = 2;

      // 작업 유형 필터
      if (operationType) {
        whereConditions.push(`operation_type = $${paramIndex}`);
        queryParams.push(operationType);
        paramIndex++;
      }

      // 변경자 필터
      if (changedBy) {
        whereConditions.push(`changed_by ILIKE $${paramIndex}`);
        queryParams.push(`%${changedBy}%`);
        paramIndex++;
      }

      // 날짜 범위 필터
      if (startDate) {
        whereConditions.push(`changed_at >= $${paramIndex}`);
        queryParams.push(startDate);
        paramIndex++;
      }
      if (endDate) {
        whereConditions.push(`changed_at <= $${paramIndex}`);
        queryParams.push(endDate);
        paramIndex++;
      }

      // LIMIT과 OFFSET 파라미터 추가
      queryParams.push(limit);
      const limitParam = `$${paramIndex}`;
      paramIndex++;

      queryParams.push(offset);
      const offsetParam = `$${paramIndex}`;

      const whereClause = whereConditions.join(" AND ");

      // 이력 조회 쿼리 (log_id로 정렬 - 시간 데이터 불일치 문제 해결)
      const historyQuery = `
        SELECT 
          log_id,
          operation_type,
          original_id,
          changed_column,
          old_value,
          new_value,
          changed_by,
          changed_at,
          ip_address,
          user_agent,
          full_row_before,
          full_row_after
        FROM ${logTableName}
        WHERE ${whereClause}
        ORDER BY log_id DESC
        LIMIT ${limitParam} OFFSET ${offsetParam}
      `;

      // 전체 카운트 쿼리
      const countQuery = `
        SELECT COUNT(*) as total
        FROM ${logTableName}
        WHERE ${whereClause}
      `;

      const [historyRecords, countResult] = await Promise.all([
        query<any>(historyQuery, queryParams),
        query<any>(countQuery, queryParams.slice(0, -2)), // LIMIT, OFFSET 제외
      ]);

      const total = parseInt(countResult[0]?.total || "0", 10);

      logger.info(`✅ 이력 조회 완료: ${historyRecords.length}건 / 전체 ${total}건`);

      res.json({
        success: true,
        data: {
          records: historyRecords,
          pagination: {
            total,
            limit: parseInt(limit as string, 10),
            offset: parseInt(offset as string, 10),
            hasMore: parseInt(offset as string, 10) + historyRecords.length < total,
          },
        },
        message: "이력 조회 성공",
      });
    } catch (error: any) {
      logger.error(`❌ 테이블 이력 조회 실패:`, error);

      // 테이블이 존재하지 않는 경우
      if (error.code === "42P01") {
        res.status(404).json({
          success: false,
          message: "이력 테이블이 존재하지 않습니다. 테이블 타입 관리에서 이력 관리를 활성화해주세요.",
          errorCode: "TABLE_NOT_FOUND",
        });
        return;
      }

      res.status(500).json({
        success: false,
        message: "이력 조회 중 오류가 발생했습니다.",
        error: error.message,
      });
    }
  }

  /**
   * 전체 테이블 이력 조회 (레코드 ID 없이)
   */
  static async getAllTableHistory(req: Request, res: Response): Promise<void> {
    try {
      const { tableName } = req.params;
      const { limit = 50, offset = 0, operationType, changedBy, startDate, endDate } = req.query;

      logger.info(`📜 전체 테이블 이력 조회 요청:`, {
        tableName,
        limit,
        offset,
      });

      // 로그 테이블명 생성
      const logTableName = `${tableName}_log`;

      // 동적 WHERE 조건 생성
      const whereConditions: string[] = [];
      const queryParams: any[] = [];
      let paramIndex = 1;

      // 작업 유형 필터
      if (operationType) {
        whereConditions.push(`operation_type = $${paramIndex}`);
        queryParams.push(operationType);
        paramIndex++;
      }

      // 변경자 필터
      if (changedBy) {
        whereConditions.push(`changed_by ILIKE $${paramIndex}`);
        queryParams.push(`%${changedBy}%`);
        paramIndex++;
      }

      // 날짜 범위 필터
      if (startDate) {
        whereConditions.push(`changed_at >= $${paramIndex}`);
        queryParams.push(startDate);
        paramIndex++;
      }
      if (endDate) {
        whereConditions.push(`changed_at <= $${paramIndex}`);
        queryParams.push(endDate);
        paramIndex++;
      }

      // LIMIT과 OFFSET 파라미터 추가
      queryParams.push(limit);
      const limitParam = `$${paramIndex}`;
      paramIndex++;

      queryParams.push(offset);
      const offsetParam = `$${paramIndex}`;

      const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";

      // 이력 조회 쿼리 (log_id로 정렬 - 시간 데이터 불일치 문제 해결)
      const historyQuery = `
        SELECT 
          log_id,
          operation_type,
          original_id,
          changed_column,
          old_value,
          new_value,
          changed_by,
          changed_at,
          ip_address,
          user_agent,
          full_row_before,
          full_row_after
        FROM ${logTableName}
        ${whereClause}
        ORDER BY log_id DESC
        LIMIT ${limitParam} OFFSET ${offsetParam}
      `;

      // 전체 카운트 쿼리
      const countQuery = `
        SELECT COUNT(*) as total
        FROM ${logTableName}
        ${whereClause}
      `;

      const [historyRecords, countResult] = await Promise.all([
        query<any>(historyQuery, queryParams),
        query<any>(countQuery, queryParams.slice(0, -2)), // LIMIT, OFFSET 제외
      ]);

      const total = parseInt(countResult[0]?.total || "0", 10);

      res.json({
        success: true,
        data: {
          records: historyRecords,
          pagination: {
            total,
            limit: Number(limit),
            offset: Number(offset),
            hasMore: Number(offset) + Number(limit) < total,
          },
        },
        message: "전체 테이블 이력 조회 성공",
      });
    } catch (error: any) {
      logger.error(`❌ 전체 테이블 이력 조회 실패:`, error);

      if (error.code === "42P01") {
        res.status(404).json({
          success: false,
          message: "이력 테이블이 존재하지 않습니다.",
          errorCode: "TABLE_NOT_FOUND",
        });
        return;
      }

      res.status(500).json({
        success: false,
        message: "이력 조회 중 오류가 발생했습니다.",
        error: error.message,
      });
    }
  }

  /**
   * 테이블 전체 이력 요약 조회
   */
  static async getTableHistorySummary(req: Request, res: Response): Promise<void> {
    try {
      const { tableName } = req.params;
      const logTableName = `${tableName}_log`;

      const summaryQuery = `
        SELECT 
          operation_type,
          COUNT(*) as count,
          COUNT(DISTINCT original_id) as affected_records,
          COUNT(DISTINCT changed_by) as unique_users,
          MIN(changed_at) as first_change,
          MAX(changed_at) as last_change
        FROM ${logTableName}
        GROUP BY operation_type
      `;

      const summary = await query<any>(summaryQuery);

      res.json({
        success: true,
        data: summary,
        message: "이력 요약 조회 성공",
      });
    } catch (error: any) {
      logger.error(`❌ 테이블 이력 요약 조회 실패:`, error);

      if (error.code === "42P01") {
        res.status(404).json({
          success: false,
          message: "이력 테이블이 존재하지 않습니다.",
          errorCode: "TABLE_NOT_FOUND",
        });
        return;
      }

      res.status(500).json({
        success: false,
        message: "이력 요약 조회 중 오류가 발생했습니다.",
        error: error.message,
      });
    }
  }

  /**
   * 특정 레코드의 변경 타임라인 조회 (그룹화)
   */
  static async getRecordTimeline(req: Request, res: Response): Promise<void> {
    try {
      const { tableName, recordId } = req.params;
      const logTableName = `${tableName}_log`;

      // 변경 이벤트별로 그룹화 (동일 시간대 변경을 하나의 이벤트로)
      const timelineQuery = `
        WITH grouped_changes AS (
          SELECT 
            changed_at,
            changed_by,
            operation_type,
            ip_address,
            json_agg(
              json_build_object(
                'column', changed_column,
                'oldValue', old_value,
                'newValue', new_value
              ) ORDER BY changed_column
            ) as changes,
            full_row_before,
            full_row_after
          FROM ${logTableName}
          WHERE original_id = $1
          GROUP BY changed_at, changed_by, operation_type, ip_address, full_row_before, full_row_after
          ORDER BY changed_at DESC
          LIMIT 100
        )
        SELECT * FROM grouped_changes
      `;

      const timeline = await query<any>(timelineQuery, [recordId]);

      res.json({
        success: true,
        data: timeline,
        message: "타임라인 조회 성공",
      });
    } catch (error: any) {
      logger.error(`❌ 레코드 타임라인 조회 실패:`, error);

      res.status(500).json({
        success: false,
        message: "타임라인 조회 중 오류가 발생했습니다.",
        error: error.message,
      });
    }
  }

  /**
   * 이력 테이블 존재 여부 확인
   */
  static async checkHistoryTableExists(req: Request, res: Response): Promise<void> {
    try {
      const { tableName } = req.params;
      const logTableName = `${tableName}_log`;

      const checkQuery = `
        SELECT EXISTS (
          SELECT FROM information_schema.tables 
          WHERE table_schema = 'public' 
          AND table_name = $1
        ) as exists
      `;

      const result = await query<any>(checkQuery, [logTableName]);
      const exists = result[0]?.exists || false;

      res.json({
        success: true,
        data: {
          tableName,
          logTableName,
          exists,
          historyEnabled: exists,
        },
        message: exists ? "이력 테이블이 존재합니다." : "이력 테이블이 존재하지 않습니다.",
      });
    } catch (error: any) {
      logger.error(`❌ 이력 테이블 존재 여부 확인 실패:`, error);

      res.status(500).json({
        success: false,
        message: "이력 테이블 확인 중 오류가 발생했습니다.",
        error: error.message,
      });
    }
  }
}

