/**
 * 상호 배제 (Mutual Exclusion) 컨트롤러
 * 두 필드가 같은 값을 선택할 수 없도록 제한하는 기능
 */

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

// =====================================================
// 상호 배제 규칙 CRUD
// =====================================================

/**
 * 상호 배제 규칙 목록 조회
 */
export const getExclusions = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const companyCode = req.user?.companyCode || "*";
    const { isActive } = req.query;

    let sql = `
      SELECT * FROM cascading_mutual_exclusion
      WHERE 1=1
    `;
    const params: any[] = [];
    let paramIndex = 1;

    // 회사 필터
    if (companyCode !== "*") {
      sql += ` AND company_code = $${paramIndex++}`;
      params.push(companyCode);
    }

    // 활성 상태 필터
    if (isActive) {
      sql += ` AND is_active = $${paramIndex++}`;
      params.push(isActive);
    }

    sql += ` ORDER BY exclusion_name`;

    const result = await query(sql, params);

    logger.info("상호 배제 규칙 목록 조회", {
      count: result.length,
      companyCode,
    });

    res.json({
      success: true,
      data: result,
    });
  } catch (error: any) {
    logger.error("상호 배제 규칙 목록 조회 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "상호 배제 규칙 목록 조회에 실패했습니다.",
      error: error.message,
    });
  }
};

/**
 * 상호 배제 규칙 상세 조회
 */
export const getExclusionDetail = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { exclusionId } = req.params;
    const companyCode = req.user?.companyCode || "*";

    let sql = `SELECT * FROM cascading_mutual_exclusion WHERE exclusion_id = $1`;
    const params: any[] = [Number(exclusionId)];

    if (companyCode !== "*") {
      sql += ` AND company_code = $2`;
      params.push(companyCode);
    }

    const result = await queryOne(sql, params);

    if (!result) {
      return res.status(404).json({
        success: false,
        message: "상호 배제 규칙을 찾을 수 없습니다.",
      });
    }

    logger.info("상호 배제 규칙 상세 조회", { exclusionId, companyCode });

    res.json({
      success: true,
      data: result,
    });
  } catch (error: any) {
    logger.error("상호 배제 규칙 상세 조회 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "상호 배제 규칙 상세 조회에 실패했습니다.",
      error: error.message,
    });
  }
};

/**
 * 배제 코드 자동 생성 함수
 */
const generateExclusionCode = async (companyCode: string): Promise<string> => {
  const prefix = "EX";
  const result = await queryOne(
    `SELECT COUNT(*) as cnt FROM cascading_mutual_exclusion WHERE company_code = $1`,
    [companyCode]
  );
  const count = parseInt(result?.cnt || "0", 10) + 1;
  const timestamp = Date.now().toString(36).toUpperCase().slice(-4);
  return `${prefix}_${timestamp}_${count.toString().padStart(3, "0")}`;
};

/**
 * 상호 배제 규칙 생성
 */
export const createExclusion = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const companyCode = req.user?.companyCode || "*";
    const {
      exclusionName,
      fieldNames, // 콤마로 구분된 필드명 (예: "source_warehouse,target_warehouse")
      sourceTable,
      valueColumn,
      labelColumn,
      exclusionType = "SAME_VALUE",
      errorMessage = "동일한 값을 선택할 수 없습니다",
    } = req.body;

    // 필수 필드 검증
    if (!exclusionName || !fieldNames || !sourceTable || !valueColumn) {
      return res.status(400).json({
        success: false,
        message:
          "필수 필드가 누락되었습니다. (exclusionName, fieldNames, sourceTable, valueColumn)",
      });
    }

    // 배제 코드 자동 생성
    const exclusionCode = await generateExclusionCode(companyCode);

    // 중복 체크 (생략 - 자동 생성이므로 중복 불가)
    const existingCheck = await queryOne(
      `SELECT exclusion_id FROM cascading_mutual_exclusion WHERE exclusion_code = $1 AND company_code = $2`,
      [exclusionCode, companyCode]
    );

    if (existingCheck) {
      return res.status(409).json({
        success: false,
        message: "이미 존재하는 배제 코드입니다.",
      });
    }

    const insertSql = `
      INSERT INTO cascading_mutual_exclusion (
        exclusion_code, exclusion_name, field_names,
        source_table, value_column, label_column,
        exclusion_type, error_message,
        company_code, is_active, created_date
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'Y', CURRENT_TIMESTAMP)
      RETURNING *
    `;

    const result = await queryOne(insertSql, [
      exclusionCode,
      exclusionName,
      fieldNames,
      sourceTable,
      valueColumn,
      labelColumn || null,
      exclusionType,
      errorMessage,
      companyCode,
    ]);

    logger.info("상호 배제 규칙 생성", { exclusionCode, companyCode });

    res.status(201).json({
      success: true,
      message: "상호 배제 규칙이 생성되었습니다.",
      data: result,
    });
  } catch (error: any) {
    logger.error("상호 배제 규칙 생성 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "상호 배제 규칙 생성에 실패했습니다.",
      error: error.message,
    });
  }
};

/**
 * 상호 배제 규칙 수정
 */
export const updateExclusion = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { exclusionId } = req.params;
    const companyCode = req.user?.companyCode || "*";
    const {
      exclusionName,
      fieldNames,
      sourceTable,
      valueColumn,
      labelColumn,
      exclusionType,
      errorMessage,
      isActive,
    } = req.body;

    // 기존 규칙 확인
    let checkSql = `SELECT * FROM cascading_mutual_exclusion WHERE exclusion_id = $1`;
    const checkParams: any[] = [Number(exclusionId)];

    if (companyCode !== "*") {
      checkSql += ` AND company_code = $2`;
      checkParams.push(companyCode);
    }

    const existing = await queryOne(checkSql, checkParams);

    if (!existing) {
      return res.status(404).json({
        success: false,
        message: "상호 배제 규칙을 찾을 수 없습니다.",
      });
    }

    const updateSql = `
      UPDATE cascading_mutual_exclusion SET
        exclusion_name = COALESCE($1, exclusion_name),
        field_names = COALESCE($2, field_names),
        source_table = COALESCE($3, source_table),
        value_column = COALESCE($4, value_column),
        label_column = COALESCE($5, label_column),
        exclusion_type = COALESCE($6, exclusion_type),
        error_message = COALESCE($7, error_message),
        is_active = COALESCE($8, is_active)
      WHERE exclusion_id = $9
      RETURNING *
    `;

    const result = await queryOne(updateSql, [
      exclusionName,
      fieldNames,
      sourceTable,
      valueColumn,
      labelColumn,
      exclusionType,
      errorMessage,
      isActive,
      Number(exclusionId),
    ]);

    logger.info("상호 배제 규칙 수정", { exclusionId, companyCode });

    res.json({
      success: true,
      message: "상호 배제 규칙이 수정되었습니다.",
      data: result,
    });
  } catch (error: any) {
    logger.error("상호 배제 규칙 수정 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "상호 배제 규칙 수정에 실패했습니다.",
      error: error.message,
    });
  }
};

/**
 * 상호 배제 규칙 삭제
 */
export const deleteExclusion = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { exclusionId } = req.params;
    const companyCode = req.user?.companyCode || "*";

    let deleteSql = `DELETE FROM cascading_mutual_exclusion WHERE exclusion_id = $1`;
    const deleteParams: any[] = [Number(exclusionId)];

    if (companyCode !== "*") {
      deleteSql += ` AND company_code = $2`;
      deleteParams.push(companyCode);
    }

    deleteSql += ` RETURNING exclusion_id`;

    const result = await queryOne(deleteSql, deleteParams);

    if (!result) {
      return res.status(404).json({
        success: false,
        message: "상호 배제 규칙을 찾을 수 없습니다.",
      });
    }

    logger.info("상호 배제 규칙 삭제", { exclusionId, companyCode });

    res.json({
      success: true,
      message: "상호 배제 규칙이 삭제되었습니다.",
    });
  } catch (error: any) {
    logger.error("상호 배제 규칙 삭제 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "상호 배제 규칙 삭제에 실패했습니다.",
      error: error.message,
    });
  }
};

// =====================================================
// 상호 배제 검증 API (실제 사용)
// =====================================================

/**
 * 상호 배제 검증
 * 선택하려는 값이 다른 필드와 충돌하는지 확인
 */
export const validateExclusion = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { exclusionCode } = req.params;
    const { fieldValues } = req.body; // { "source_warehouse": "WH001", "target_warehouse": "WH002" }
    const companyCode = req.user?.companyCode || "*";

    // 배제 규칙 조회
    let exclusionSql = `SELECT * FROM cascading_mutual_exclusion WHERE exclusion_code = $1 AND is_active = 'Y'`;
    const exclusionParams: any[] = [exclusionCode];

    if (companyCode !== "*") {
      exclusionSql += ` AND company_code = $2`;
      exclusionParams.push(companyCode);
    }

    const exclusion = await queryOne(exclusionSql, exclusionParams);

    if (!exclusion) {
      return res.status(404).json({
        success: false,
        message: "상호 배제 규칙을 찾을 수 없습니다.",
      });
    }

    // 필드명 파싱
    const fields = exclusion.field_names
      .split(",")
      .map((f: string) => f.trim());

    // 필드 값 수집
    const values: string[] = [];
    for (const field of fields) {
      if (fieldValues[field]) {
        values.push(fieldValues[field]);
      }
    }

    // 상호 배제 검증
    let isValid = true;
    let errorMessage = null;
    let conflictingFields: string[] = [];

    if (exclusion.exclusion_type === "SAME_VALUE") {
      // 같은 값이 있는지 확인
      const uniqueValues = new Set(values);
      if (uniqueValues.size !== values.length) {
        isValid = false;
        errorMessage = exclusion.error_message;

        // 충돌하는 필드 찾기
        const valueCounts: Record<string, string[]> = {};
        for (const field of fields) {
          const val = fieldValues[field];
          if (val) {
            if (!valueCounts[val]) {
              valueCounts[val] = [];
            }
            valueCounts[val].push(field);
          }
        }

        for (const [, fieldList] of Object.entries(valueCounts)) {
          if (fieldList.length > 1) {
            conflictingFields = fieldList;
            break;
          }
        }
      }
    }

    logger.info("상호 배제 검증", {
      exclusionCode,
      isValid,
      fieldValues,
    });

    res.json({
      success: true,
      data: {
        isValid,
        errorMessage: isValid ? null : errorMessage,
        conflictingFields,
      },
    });
  } catch (error: any) {
    logger.error("상호 배제 검증 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "상호 배제 검증에 실패했습니다.",
      error: error.message,
    });
  }
};

/**
 * 필드에 대한 배제 옵션 조회
 * 다른 필드에서 이미 선택한 값을 제외한 옵션 반환
 */
export const getExcludedOptions = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { exclusionCode } = req.params;
    const { currentField, selectedValues } = req.query; // selectedValues: 이미 선택된 값들 (콤마 구분)
    const companyCode = req.user?.companyCode || "*";

    // 배제 규칙 조회
    let exclusionSql = `SELECT * FROM cascading_mutual_exclusion WHERE exclusion_code = $1 AND is_active = 'Y'`;
    const exclusionParams: any[] = [exclusionCode];

    if (companyCode !== "*") {
      exclusionSql += ` AND company_code = $2`;
      exclusionParams.push(companyCode);
    }

    const exclusion = await queryOne(exclusionSql, exclusionParams);

    if (!exclusion) {
      return res.status(404).json({
        success: false,
        message: "상호 배제 규칙을 찾을 수 없습니다.",
      });
    }

    // 옵션 조회
    const labelColumn = exclusion.label_column || exclusion.value_column;
    let optionsSql = `
      SELECT 
        ${exclusion.value_column} as value,
        ${labelColumn} as label
      FROM ${exclusion.source_table}
      WHERE 1=1
    `;
    const optionsParams: any[] = [];
    let optionsParamIndex = 1;

    // 멀티테넌시 필터
    if (companyCode !== "*") {
      const columnCheck = await queryOne(
        `SELECT column_name FROM information_schema.columns 
         WHERE table_name = $1 AND column_name = 'company_code'`,
        [exclusion.source_table]
      );

      if (columnCheck) {
        optionsSql += ` AND company_code = $${optionsParamIndex++}`;
        optionsParams.push(companyCode);
      }
    }

    // 이미 선택된 값 제외
    if (selectedValues) {
      const excludeValues = (selectedValues as string)
        .split(",")
        .map((v) => v.trim())
        .filter((v) => v);
      if (excludeValues.length > 0) {
        const placeholders = excludeValues
          .map((_, i) => `$${optionsParamIndex + i}`)
          .join(",");
        optionsSql += ` AND ${exclusion.value_column} NOT IN (${placeholders})`;
        optionsParams.push(...excludeValues);
      }
    }

    optionsSql += ` ORDER BY ${labelColumn}`;

    const optionsResult = await query(optionsSql, optionsParams);

    logger.info("상호 배제 옵션 조회", {
      exclusionCode,
      currentField,
      excludedCount: (selectedValues as string)?.split(",").length || 0,
      optionCount: optionsResult.length,
    });

    res.json({
      success: true,
      data: optionsResult,
    });
  } catch (error: any) {
    logger.error("상호 배제 옵션 조회 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "상호 배제 옵션 조회에 실패했습니다.",
      error: error.message,
    });
  }
};
