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

export interface EntityReferenceOption {
  value: string;
  label: string;
}

export interface EntityReferenceData {
  options: EntityReferenceOption[];
  referenceInfo: {
    referenceTable: string;
    referenceColumn: string;
    displayColumn: string | null;
  };
}

export interface CodeReferenceData {
  options: EntityReferenceOption[];
  codeCategory: string;
}

export class EntityReferenceController {
  /**
   * 엔티티 참조 데이터 조회
   * GET /api/entity-reference/:tableName/:columnName
   */
  static async getEntityReferenceData(req: Request, res: Response) {
    try {
      const { tableName, columnName } = req.params;
      const { limit = 100, search } = req.query;
      // 멀티테넌시: 인증된 사용자의 회사 코드
      const companyCode = (req as any).user?.companyCode;

      logger.info(`엔티티 참조 데이터 조회 요청: ${tableName}.${columnName}`, {
        limit,
        search,
        companyCode,
      });

      // 컬럼 정보 조회 (table_type_columns에서)
      const columnInfo = await queryOne<any>(
        `SELECT * FROM table_type_columns
         WHERE table_name = $1 AND column_name = $2 AND company_code = '*'
         LIMIT 1`,
        [tableName, columnName]
      );

      if (!columnInfo) {
        return res.status(404).json({
          success: false,
          message: `컬럼 정보를 찾을 수 없습니다: ${tableName}.${columnName}`,
        });
      }

      // inputType 확인
      if (columnInfo.input_type !== "entity") {
        return res.status(400).json({
          success: false,
          message: `컬럼 '${tableName}.${columnName}'은 entity 타입이 아닙니다. inputType: ${columnInfo.input_type}`,
        });
      }

      // table_type_columns에서 직접 참조 정보 가져오기
      const referenceTable = columnInfo.reference_table;
      const referenceColumn = columnInfo.reference_column;
      const displayColumn = columnInfo.display_column || "name";

      // entity 타입인데 참조 테이블 정보가 없으면 오류
      if (!referenceTable || !referenceColumn) {
        return res.status(400).json({
          success: false,
          message: `Entity 타입 컬럼 '${tableName}.${columnName}'에 참조 테이블 정보가 설정되지 않았습니다. table_type_columns에서 reference_table과 reference_column을 확인해주세요.`,
        });
      }

      // 참조 테이블이 실제로 존재하는지 확인
      try {
        await query<any>(`SELECT 1 FROM ${referenceTable} LIMIT 1`);
        logger.info(
          `Entity 참조 설정: ${tableName}.${columnName} -> ${referenceTable}.${referenceColumn} (display: ${displayColumn})`
        );
      } catch (error) {
        logger.error(
          `참조 테이블 '${referenceTable}'이 존재하지 않습니다:`,
          error
        );
        return res.status(400).json({
          success: false,
          message: `참조 테이블 '${referenceTable}'이 존재하지 않습니다. table_type_columns의 reference_table 설정을 확인해주세요.`,
        });
      }

      // 참조 테이블에 company_code 컬럼이 있는지 확인
      const hasCompanyCode = await queryOne<any>(
        `SELECT column_name FROM information_schema.columns 
         WHERE table_name = $1 AND column_name = 'company_code' AND table_schema = 'public'`,
        [referenceTable]
      );

      // 동적 쿼리로 참조 데이터 조회 (멀티테넌시 필터 적용)
      const whereConditions: string[] = [];
      const queryParams: any[] = [];

      // 멀티테넌시: company_code 필터링 (참조 테이블에 company_code가 있는 경우)
      if (hasCompanyCode && companyCode && companyCode !== "*") {
        queryParams.push(companyCode);
        whereConditions.push(`company_code = $${queryParams.length}`);
        logger.info(`멀티테넌시 필터 적용: company_code = ${companyCode}`, { referenceTable });
      }

      // 검색 조건 추가
      if (search) {
        queryParams.push(`%${search}%`);
        whereConditions.push(`${displayColumn} ILIKE $${queryParams.length}`);
      }

      let sqlQuery = `SELECT ${referenceColumn}, ${displayColumn} as display_name FROM ${referenceTable}`;
      if (whereConditions.length > 0) {
        sqlQuery += ` WHERE ${whereConditions.join(" AND ")}`;
      }
      sqlQuery += ` ORDER BY ${displayColumn} LIMIT $${queryParams.length + 1}`;
      queryParams.push(Number(limit));

      logger.info(`실행할 쿼리: ${sqlQuery}`, {
        queryParams,
        referenceTable,
        referenceColumn,
        displayColumn,
        companyCode,
      });

      const referenceData = await query<any>(sqlQuery, queryParams);

      // 옵션 형태로 변환
      const options: EntityReferenceOption[] = (referenceData as any[]).map(
        (row) => ({
          value: String(row[referenceColumn]),
          label: String(row.display_name || row[referenceColumn]),
        })
      );

      logger.info(`엔티티 참조 데이터 조회 완료: ${options.length}개 항목`, { companyCode });

      return res.json({
        success: true,
        data: {
          options,
          referenceInfo: {
            referenceTable,
            referenceColumn,
            displayColumn,
          },
        },
      });
    } catch (error) {
      logger.error("엔티티 참조 데이터 조회 실패:", error);
      return res.status(500).json({
        success: false,
        message: "엔티티 참조 데이터 조회 중 오류가 발생했습니다.",
      });
    }
  }

  /**
   * 공통 코드 데이터 조회
   * GET /api/entity-reference/code/:codeCategory
   */
  static async getCodeData(req: Request, res: Response) {
    try {
      const { codeCategory } = req.params;
      const { limit = 100, search } = req.query;
      // 멀티테넌시: 인증된 사용자의 회사 코드
      const companyCode = (req as any).user?.companyCode;

      logger.info(`공통 코드 데이터 조회 요청: ${codeCategory}`, {
        limit,
        search,
        companyCode,
      });

      // code_info 테이블에서 코드 데이터 조회 (멀티테넌시 필터 적용)
      const queryParams: any[] = [codeCategory, 'Y'];
      let sqlQuery = `
        SELECT code_value, code_name
        FROM code_info
        WHERE code_category = $1 AND is_active = $2
      `;

      // 멀티테넌시: company_code 필터링
      if (companyCode && companyCode !== "*") {
        queryParams.push(companyCode);
        sqlQuery += ` AND company_code = $${queryParams.length}`;
        logger.info(`공통 코드 멀티테넌시 필터 적용: company_code = ${companyCode}`);
      }

      if (search) {
        queryParams.push(`%${search}%`);
        sqlQuery += ` AND code_name ILIKE $${queryParams.length}`;
      }

      sqlQuery += ` ORDER BY code_name ASC LIMIT $${queryParams.length + 1}`;
      queryParams.push(Number(limit));

      const codeData = await query<any>(sqlQuery, queryParams);

      // 옵션 형태로 변환
      const options: EntityReferenceOption[] = codeData.map((code: any) => ({
        value: code.code_value,
        label: code.code_name,
      }));

      logger.info(`공통 코드 데이터 조회 완료: ${options.length}개 항목`, { companyCode });

      return res.json({
        success: true,
        data: {
          options,
          codeCategory,
        },
      });
    } catch (error) {
      logger.error("공통 코드 데이터 조회 실패:", error);
      return res.status(500).json({
        success: false,
        message: "공통 코드 데이터 조회 중 오류가 발생했습니다.",
      });
    }
  }
}
