import { Request, Response } from "express";
import { logger } from "../utils/logger";
import { TableManagementService } from "../services/tableManagementService";
import { entityJoinService } from "../services/entityJoinService";
import { referenceCacheService } from "../services/referenceCacheService";

const tableManagementService = new TableManagementService();

/**
 * Entity 조인 기능 컨트롤러
 * ID값을 의미있는 데이터로 자동 변환하는 API 제공
 */
export class EntityJoinController {
  /**
   * Entity 조인이 포함된 테이블 데이터 조회
   * GET /api/table-management/tables/:tableName/data-with-joins
   */
  async getTableDataWithJoins(req: Request, res: Response): Promise<void> {
    try {
      const { tableName } = req.params;
      const {
        page = 1,
        size = 20,
        search,
        sortBy,
        sortOrder = "asc",
        enableEntityJoin = true,
        additionalJoinColumns, // 추가 조인 컬럼 정보 (JSON 문자열)
        screenEntityConfigs, // 화면별 엔티티 설정 (JSON 문자열)
        autoFilter, // 🔒 멀티테넌시 자동 필터
        dataFilter, // 🆕 데이터 필터 (JSON 문자열)
        excludeFilter, // 🆕 제외 필터 (JSON 문자열) - 다른 테이블에 이미 존재하는 데이터 제외
        userLang, // userLang은 별도로 분리하여 search에 포함되지 않도록 함
        ...otherParams
      } = req.query;

      logger.info(`Entity 조인 데이터 요청: ${tableName}`, {
        page,
        size,
        enableEntityJoin,
        search,
        autoFilter,
      });

      // 검색 조건 처리
      let searchConditions: Record<string, any> = {};
      if (search) {
        try {
          // search가 문자열인 경우 JSON 파싱
          searchConditions =
            typeof search === "string" ? JSON.parse(search) : search;
        } catch (error) {
          logger.warn("검색 조건 파싱 오류:", error);
          searchConditions = {};
        }
      }

      // 🔒 멀티테넌시: 자동 필터 처리
      if (autoFilter) {
        try {
          const parsedAutoFilter =
            typeof autoFilter === "string" ? JSON.parse(autoFilter) : autoFilter;

          if (parsedAutoFilter.enabled && (req as any).user) {
            const filterColumn = parsedAutoFilter.filterColumn || "company_code";
            const userField = parsedAutoFilter.userField || "companyCode";
            const userValue = ((req as any).user as any)[userField];

            // 🆕 프리뷰용 회사 코드 오버라이드 (최고 관리자만 허용)
            let finalCompanyCode = userValue;
            if (parsedAutoFilter.companyCodeOverride && userValue === "*") {
              // 최고 관리자만 다른 회사 코드로 오버라이드 가능
              finalCompanyCode = parsedAutoFilter.companyCodeOverride;
              logger.info("🔓 최고 관리자 회사 코드 오버라이드:", {
                originalCompanyCode: userValue,
                overrideCompanyCode: parsedAutoFilter.companyCodeOverride,
                tableName,
              });
            }

            if (finalCompanyCode) {
              searchConditions[filterColumn] = finalCompanyCode;
              logger.info("🔒 Entity 조인에 멀티테넌시 필터 적용:", {
                filterColumn,
                finalCompanyCode,
                tableName,
              });
            }
          }
        } catch (error) {
          logger.warn("자동 필터 파싱 오류:", error);
        }
      }

      // 추가 조인 컬럼 정보 처리
      let parsedAdditionalJoinColumns: any[] = [];
      if (additionalJoinColumns) {
        try {
          parsedAdditionalJoinColumns =
            typeof additionalJoinColumns === "string"
              ? JSON.parse(additionalJoinColumns)
              : additionalJoinColumns;
          logger.info("추가 조인 컬럼 파싱 완료:", parsedAdditionalJoinColumns);
        } catch (error) {
          logger.warn("추가 조인 컬럼 파싱 오류:", error);
          parsedAdditionalJoinColumns = [];
        }
      }

      // 화면별 엔티티 설정 처리
      let parsedScreenEntityConfigs: Record<string, any> = {};
      if (screenEntityConfigs) {
        try {
          parsedScreenEntityConfigs =
            typeof screenEntityConfigs === "string"
              ? JSON.parse(screenEntityConfigs)
              : screenEntityConfigs;
          logger.info(
            "화면별 엔티티 설정 파싱 완료:",
            parsedScreenEntityConfigs
          );
        } catch (error) {
          logger.warn("화면별 엔티티 설정 파싱 오류:", error);
          parsedScreenEntityConfigs = {};
        }
      }

      // 🆕 데이터 필터 처리
      let parsedDataFilter: any = undefined;
      if (dataFilter) {
        try {
          parsedDataFilter =
            typeof dataFilter === "string" ? JSON.parse(dataFilter) : dataFilter;
          logger.info("데이터 필터 파싱 완료:", parsedDataFilter);
        } catch (error) {
          logger.warn("데이터 필터 파싱 오류:", error);
          parsedDataFilter = undefined;
        }
      }

      // 🆕 제외 필터 처리 (다른 테이블에 이미 존재하는 데이터 제외)
      let parsedExcludeFilter: any = undefined;
      if (excludeFilter) {
        try {
          parsedExcludeFilter =
            typeof excludeFilter === "string" ? JSON.parse(excludeFilter) : excludeFilter;
          logger.info("제외 필터 파싱 완료:", parsedExcludeFilter);
        } catch (error) {
          logger.warn("제외 필터 파싱 오류:", error);
          parsedExcludeFilter = undefined;
        }
      }

      const result = await tableManagementService.getTableDataWithEntityJoins(
        tableName,
        {
          page: Number(page),
          size: Number(size),
          search:
            Object.keys(searchConditions).length > 0
              ? searchConditions
              : undefined,
          sortBy: sortBy as string,
          sortOrder: sortOrder as string,
          enableEntityJoin:
            enableEntityJoin === "true" || enableEntityJoin === true,
          additionalJoinColumns: parsedAdditionalJoinColumns,
          screenEntityConfigs: parsedScreenEntityConfigs,
          dataFilter: parsedDataFilter, // 🆕 데이터 필터 전달
          excludeFilter: parsedExcludeFilter, // 🆕 제외 필터 전달
        }
      );

      res.status(200).json({
        success: true,
        message: "Entity 조인 데이터 조회 성공",
        data: result,
      });
    } catch (error) {
      logger.error("Entity 조인 데이터 조회 실패", error);
      res.status(500).json({
        success: false,
        message: "Entity 조인 데이터 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "Unknown error",
      });
    }
  }

  /**
   * 테이블의 Entity 조인 설정 조회
   * GET /api/table-management/tables/:tableName/entity-joins
   */
  async getEntityJoinConfigs(req: Request, res: Response): Promise<void> {
    try {
      const { tableName } = req.params;
      const companyCode = (req as any).user?.companyCode;

      logger.info(`Entity 조인 설정 조회: ${tableName} (companyCode: ${companyCode})`);

      const joinConfigs = await entityJoinService.detectEntityJoins(tableName, undefined, companyCode);

      res.status(200).json({
        success: true,
        message: "Entity 조인 설정 조회 성공",
        data: {
          tableName,
          joinConfigs,
          count: joinConfigs.length,
        },
      });
    } catch (error) {
      logger.error("Entity 조인 설정 조회 실패", error);
      res.status(500).json({
        success: false,
        message: "Entity 조인 설정 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "Unknown error",
      });
    }
  }

  /**
   * 참조 테이블의 표시 가능한 컬럼 목록 조회
   * GET /api/table-management/reference-tables/:tableName/columns
   */
  async getReferenceTableColumns(req: Request, res: Response): Promise<void> {
    try {
      const { tableName } = req.params;
      const companyCode = (req as any).user?.companyCode;

      logger.info(`참조 테이블 컬럼 조회: ${tableName} (companyCode: ${companyCode})`);

      const columns =
        await tableManagementService.getReferenceTableColumns(tableName, companyCode);

      res.status(200).json({
        success: true,
        message: "참조 테이블 컬럼 조회 성공",
        data: {
          tableName,
          columns,
          count: columns.length,
        },
      });
    } catch (error) {
      logger.error("참조 테이블 컬럼 조회 실패", error);
      res.status(500).json({
        success: false,
        message: "참조 테이블 컬럼 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "Unknown error",
      });
    }
  }

  /**
   * 컬럼 Entity 설정 업데이트 (display_column 포함)
   * PUT /api/table-management/tables/:tableName/columns/:columnName/entity-settings
   */
  async updateEntitySettings(req: Request, res: Response): Promise<void> {
    try {
      const { tableName, columnName } = req.params;
      const {
        webType,
        referenceTable,
        referenceColumn,
        displayColumn,
        columnLabel,
        description,
      } = req.body;

      logger.info(`Entity 설정 업데이트: ${tableName}.${columnName}`, req.body);

      // Entity 타입인 경우 필수 필드 검증
      if (webType === "entity") {
        if (!referenceTable || !referenceColumn) {
          res.status(400).json({
            success: false,
            message:
              "Entity 타입의 경우 referenceTable과 referenceColumn이 필수입니다.",
          });
          return;
        }
      }

      await tableManagementService.updateColumnLabel(tableName, columnName, {
        webType,
        referenceTable,
        referenceColumn,
        displayColumn,
        columnLabel,
        description,
      });

      // Entity 설정 변경 시 관련 캐시 무효화
      if (webType === "entity" && referenceTable) {
        referenceCacheService.invalidateCache(
          referenceTable,
          referenceColumn,
          displayColumn
        );
      }

      res.status(200).json({
        success: true,
        message: "Entity 설정 업데이트 성공",
        data: {
          tableName,
          columnName,
          settings: {
            webType,
            referenceTable,
            referenceColumn,
            displayColumn,
          },
        },
      });
    } catch (error) {
      logger.error("Entity 설정 업데이트 실패", error);
      res.status(500).json({
        success: false,
        message: "Entity 설정 업데이트 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "Unknown error",
      });
    }
  }

  /**
   * 캐시 상태 조회
   * GET /api/table-management/cache/status
   */
  async getCacheStatus(req: Request, res: Response): Promise<void> {
    try {
      logger.info("캐시 상태 조회");

      const cacheInfo = referenceCacheService.getCacheInfo();
      const overallHitRate = referenceCacheService.getOverallCacheHitRate();

      res.status(200).json({
        success: true,
        message: "캐시 상태 조회 성공",
        data: {
          overallHitRate,
          caches: cacheInfo,
          summary: {
            totalCaches: cacheInfo.length,
            totalSize: cacheInfo.reduce(
              (sum, cache) => sum + cache.dataSize,
              0
            ),
            averageHitRate:
              cacheInfo.length > 0
                ? cacheInfo.reduce((sum, cache) => sum + cache.hitRate, 0) /
                  cacheInfo.length
                : 0,
          },
        },
      });
    } catch (error) {
      logger.error("캐시 상태 조회 실패", error);
      res.status(500).json({
        success: false,
        message: "캐시 상태 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "Unknown error",
      });
    }
  }

  /**
   * 캐시 무효화
   * DELETE /api/table-management/cache
   */
  async invalidateCache(req: Request, res: Response): Promise<void> {
    try {
      const { table, keyColumn, displayColumn } = req.query;

      logger.info("캐시 무효화 요청", { table, keyColumn, displayColumn });

      if (table && keyColumn && displayColumn) {
        // 특정 캐시만 무효화
        referenceCacheService.invalidateCache(
          table as string,
          keyColumn as string,
          displayColumn as string
        );
      } else {
        // 전체 캐시 무효화
        referenceCacheService.invalidateCache();
      }

      res.status(200).json({
        success: true,
        message: "캐시 무효화 완료",
        data: {
          target: table ? `${table}.${keyColumn}.${displayColumn}` : "전체",
        },
      });
    } catch (error) {
      logger.error("캐시 무효화 실패", error);
      res.status(500).json({
        success: false,
        message: "캐시 무효화 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "Unknown error",
      });
    }
  }

  /**
   * Entity 조인된 테이블의 추가 컬럼 목록 조회
   * GET /api/table-management/tables/:tableName/entity-join-columns
   */
  async getEntityJoinColumns(req: Request, res: Response): Promise<void> {
    try {
      const { tableName } = req.params;
      const companyCode = (req as any).user?.companyCode;

      logger.info(`Entity 조인 컬럼 조회: ${tableName} (companyCode: ${companyCode})`);

      // 1. 현재 테이블의 Entity 조인 설정 조회
      const allJoinConfigs = await entityJoinService.detectEntityJoins(tableName, undefined, companyCode);
      
      // 🆕 화면 디자이너용: category_values는 카테고리 드롭다운용이므로 제외
      // 카테고리 값은 엔티티 조인 컬럼이 아니라 셀렉트박스 옵션으로 사용됨
      const joinConfigs = allJoinConfigs.filter(
        (config) => config.referenceTable !== "category_values"
      );

      if (joinConfigs.length === 0) {
        res.status(200).json({
          success: true,
          message: "Entity 조인 설정이 없습니다.",
          data: {
            tableName,
            joinTables: [],
            availableColumns: [],
          },
        });
        return;
      }

      // 2. 각 조인 테이블의 컬럼 정보 조회
      const joinTablesInfo = await Promise.all(
        joinConfigs.map(async (config) => {
          try {
            const columns =
              await tableManagementService.getReferenceTableColumns(
                config.referenceTable, companyCode
              );

            // 현재 display_column 정보 (참고용으로만 사용, 필터링하지 않음)
            const currentDisplayColumn =
              config.displayColumn || config.displayColumns[0];
            
            // 모든 컬럼 표시 (기본 표시 컬럼도 포함)
            return {
              joinConfig: config,
              tableName: config.referenceTable,
              currentDisplayColumn: currentDisplayColumn,
              availableColumns: columns.map((col) => ({
                columnName: col.columnName,
                columnLabel: col.displayName || col.columnName,
                dataType: col.dataType,
                inputType: col.inputType || "text",
                isNullable: true, // 기본값으로 설정
                maxLength: undefined, // 정보가 없으므로 undefined
                description: col.displayName,
              })),
            };
          } catch (error) {
            logger.warn(
              `참조 테이블 컬럼 조회 실패: ${config.referenceTable}`,
              error
            );
            return {
              joinConfig: config,
              tableName: config.referenceTable,
              currentDisplayColumn:
                config.displayColumn || config.displayColumns[0],
              availableColumns: [],
              error: error instanceof Error ? error.message : "Unknown error",
            };
          }
        })
      );

      // 3. 사용 가능한 모든 컬럼 목록 생성 (중복 제거)
      const allAvailableColumns: Array<{
        tableName: string;
        columnName: string;
        columnLabel: string;
        dataType: string;
        inputType: string;
        joinAlias: string;
        suggestedLabel: string;
      }> = [];

      joinTablesInfo.forEach((info) => {
        info.availableColumns.forEach((col) => {
          const joinAlias = `${info.joinConfig.sourceColumn}_${col.columnName}`;
          const suggestedLabel = col.columnLabel; // 라벨명만 사용

          allAvailableColumns.push({
            tableName: info.tableName,
            columnName: col.columnName,
            columnLabel: col.columnLabel,
            dataType: col.dataType,
            inputType: col.inputType || "text",
            joinAlias,
            suggestedLabel,
          });
        });
      });

      res.status(200).json({
        success: true,
        message: "Entity 조인 컬럼 조회 성공",
        data: {
          tableName,
          joinTables: joinTablesInfo,
          availableColumns: allAvailableColumns,
          summary: {
            totalJoinTables: joinConfigs.length,
            totalAvailableColumns: allAvailableColumns.length,
          },
        },
      });
    } catch (error) {
      logger.error("Entity 조인 컬럼 조회 실패", error);
      res.status(500).json({
        success: false,
        message: "Entity 조인 컬럼 조회 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "Unknown error",
      });
    }
  }

  /**
   * 공통 참조 테이블 자동 캐싱
   * POST /api/table-management/cache/preload
   */
  async preloadCommonCaches(req: Request, res: Response): Promise<void> {
    try {
      logger.info("공통 참조 테이블 자동 캐싱 시작");

      await referenceCacheService.autoPreloadCommonTables();

      const cacheInfo = referenceCacheService.getCacheInfo();

      res.status(200).json({
        success: true,
        message: "공통 참조 테이블 캐싱 완료",
        data: {
          preloadedCaches: cacheInfo.length,
          caches: cacheInfo,
        },
      });
    } catch (error) {
      logger.error("공통 참조 테이블 캐싱 실패", error);
      res.status(500).json({
        success: false,
        message: "공통 참조 테이블 캐싱 중 오류가 발생했습니다.",
        error: error instanceof Error ? error.message : "Unknown error",
      });
    }
  }
}

export const entityJoinController = new EntityJoinController();
