/**
 * 다단계 계층 (Hierarchy) 컨트롤러
 * 국가 > 도시 > 구/군 같은 다단계 연쇄 드롭다운 관리
 */

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

// =====================================================
// 계층 그룹 CRUD
// =====================================================

/**
 * 계층 그룹 목록 조회
 */
export const getHierarchyGroups = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const companyCode = req.user?.companyCode || "*";
    const { isActive, hierarchyType } = req.query;

    let sql = `
      SELECT g.*, 
        (SELECT COUNT(*) FROM cascading_hierarchy_level l WHERE l.group_code = g.group_code AND l.company_code = g.company_code) as level_count
      FROM cascading_hierarchy_group g
      WHERE 1=1
    `;
    const params: any[] = [];
    let paramIndex = 1;

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

    if (isActive) {
      sql += ` AND g.is_active = $${paramIndex++}`;
      params.push(isActive);
    }

    if (hierarchyType) {
      sql += ` AND g.hierarchy_type = $${paramIndex++}`;
      params.push(hierarchyType);
    }

    sql += ` ORDER BY g.group_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 getHierarchyGroupDetail = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { groupCode } = req.params;
    const companyCode = req.user?.companyCode || "*";

    // 그룹 조회
    let groupSql = `SELECT * FROM cascading_hierarchy_group WHERE group_code = $1`;
    const groupParams: any[] = [groupCode];

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

    const group = await queryOne(groupSql, groupParams);

    if (!group) {
      return res.status(404).json({
        success: false,
        message: "계층 그룹을 찾을 수 없습니다.",
      });
    }

    // 레벨 조회
    let levelSql = `SELECT * FROM cascading_hierarchy_level WHERE group_code = $1`;
    const levelParams: any[] = [groupCode];

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

    levelSql += ` ORDER BY level_order`;

    const levels = await query(levelSql, levelParams);

    logger.info("계층 그룹 상세 조회", { groupCode, companyCode });

    res.json({
      success: true,
      data: {
        ...group,
        levels: levels,
      },
    });
  } catch (error: any) {
    logger.error("계층 그룹 상세 조회 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "계층 그룹 상세 조회에 실패했습니다.",
      error: error.message,
    });
  }
};

/**
 * 계층 그룹 코드 자동 생성 함수
 */
const generateHierarchyGroupCode = async (
  companyCode: string
): Promise<string> => {
  const prefix = "HG";
  const result = await queryOne(
    `SELECT COUNT(*) as cnt FROM cascading_hierarchy_group 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 createHierarchyGroup = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const companyCode = req.user?.companyCode || "*";
    const userId = req.user?.userId || "system";
    const {
      groupName,
      description,
      hierarchyType = "MULTI_TABLE",
      maxLevels,
      isFixedLevels = "Y",
      // Self-reference 설정
      selfRefTable,
      selfRefIdColumn,
      selfRefParentColumn,
      selfRefValueColumn,
      selfRefLabelColumn,
      selfRefLevelColumn,
      selfRefOrderColumn,
      // BOM 설정
      bomTable,
      bomParentColumn,
      bomChildColumn,
      bomItemTable,
      bomItemIdColumn,
      bomItemLabelColumn,
      bomQtyColumn,
      bomLevelColumn,
      // 메시지
      emptyMessage,
      noOptionsMessage,
      loadingMessage,
      // 레벨 (MULTI_TABLE 타입인 경우)
      levels = [],
    } = req.body;

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

    // 그룹 코드 자동 생성
    const groupCode = await generateHierarchyGroupCode(companyCode);

    // 그룹 생성
    const insertGroupSql = `
      INSERT INTO cascading_hierarchy_group (
        group_code, group_name, description, hierarchy_type,
        max_levels, is_fixed_levels,
        self_ref_table, self_ref_id_column, self_ref_parent_column, 
        self_ref_value_column, self_ref_label_column, self_ref_level_column, self_ref_order_column,
        bom_table, bom_parent_column, bom_child_column, 
        bom_item_table, bom_item_id_column, bom_item_label_column, bom_qty_column, bom_level_column,
        empty_message, no_options_message, loading_message,
        company_code, is_active, created_by, created_date
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, 'Y', $26, CURRENT_TIMESTAMP)
      RETURNING *
    `;

    const group = await queryOne(insertGroupSql, [
      groupCode,
      groupName,
      description || null,
      hierarchyType,
      maxLevels || null,
      isFixedLevels,
      selfRefTable || null,
      selfRefIdColumn || null,
      selfRefParentColumn || null,
      selfRefValueColumn || null,
      selfRefLabelColumn || null,
      selfRefLevelColumn || null,
      selfRefOrderColumn || null,
      bomTable || null,
      bomParentColumn || null,
      bomChildColumn || null,
      bomItemTable || null,
      bomItemIdColumn || null,
      bomItemLabelColumn || null,
      bomQtyColumn || null,
      bomLevelColumn || null,
      emptyMessage || "선택해주세요",
      noOptionsMessage || "옵션이 없습니다",
      loadingMessage || "로딩 중...",
      companyCode,
      userId,
    ]);

    // 레벨 생성 (MULTI_TABLE 타입인 경우)
    if (hierarchyType === "MULTI_TABLE" && levels.length > 0) {
      for (const level of levels) {
        await query(
          `INSERT INTO cascading_hierarchy_level (
            group_code, company_code, level_order, level_name, level_code,
            table_name, value_column, label_column, parent_key_column,
            filter_column, filter_value, order_column, order_direction,
            placeholder, is_required, is_searchable, is_active, created_date
          ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, 'Y', CURRENT_TIMESTAMP)`,
          [
            groupCode,
            companyCode,
            level.levelOrder,
            level.levelName,
            level.levelCode || null,
            level.tableName,
            level.valueColumn,
            level.labelColumn,
            level.parentKeyColumn || null,
            level.filterColumn || null,
            level.filterValue || null,
            level.orderColumn || null,
            level.orderDirection || "ASC",
            level.placeholder || `${level.levelName} 선택`,
            level.isRequired || "Y",
            level.isSearchable || "N",
          ]
        );
      }
    }

    logger.info("계층 그룹 생성", { groupCode, hierarchyType, companyCode });

    res.status(201).json({
      success: true,
      message: "계층 그룹이 생성되었습니다.",
      data: group,
    });
  } catch (error: any) {
    logger.error("계층 그룹 생성 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "계층 그룹 생성에 실패했습니다.",
      error: error.message,
    });
  }
};

/**
 * 계층 그룹 수정
 */
export const updateHierarchyGroup = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { groupCode } = req.params;
    const companyCode = req.user?.companyCode || "*";
    const userId = req.user?.userId || "system";
    const {
      groupName,
      description,
      maxLevels,
      isFixedLevels,
      emptyMessage,
      noOptionsMessage,
      loadingMessage,
      isActive,
    } = req.body;

    // 기존 그룹 확인
    let checkSql = `SELECT * FROM cascading_hierarchy_group WHERE group_code = $1`;
    const checkParams: any[] = [groupCode];

    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_hierarchy_group SET
        group_name = COALESCE($1, group_name),
        description = COALESCE($2, description),
        max_levels = COALESCE($3, max_levels),
        is_fixed_levels = COALESCE($4, is_fixed_levels),
        empty_message = COALESCE($5, empty_message),
        no_options_message = COALESCE($6, no_options_message),
        loading_message = COALESCE($7, loading_message),
        is_active = COALESCE($8, is_active),
        updated_by = $9,
        updated_date = CURRENT_TIMESTAMP
      WHERE group_code = $10 AND company_code = $11
      RETURNING *
    `;

    const result = await queryOne(updateSql, [
      groupName,
      description,
      maxLevels,
      isFixedLevels,
      emptyMessage,
      noOptionsMessage,
      loadingMessage,
      isActive,
      userId,
      groupCode,
      existing.company_code,
    ]);

    logger.info("계층 그룹 수정", { groupCode, 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 deleteHierarchyGroup = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { groupCode } = req.params;
    const companyCode = req.user?.companyCode || "*";

    // 레벨 먼저 삭제
    let deleteLevelsSql = `DELETE FROM cascading_hierarchy_level WHERE group_code = $1`;
    const levelParams: any[] = [groupCode];

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

    await query(deleteLevelsSql, levelParams);

    // 그룹 삭제
    let deleteGroupSql = `DELETE FROM cascading_hierarchy_group WHERE group_code = $1`;
    const groupParams: any[] = [groupCode];

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

    deleteGroupSql += ` RETURNING group_code`;

    const result = await queryOne(deleteGroupSql, groupParams);

    if (!result) {
      return res.status(404).json({
        success: false,
        message: "계층 그룹을 찾을 수 없습니다.",
      });
    }

    logger.info("계층 그룹 삭제", { groupCode, companyCode });

    res.json({
      success: true,
      message: "계층 그룹이 삭제되었습니다.",
    });
  } catch (error: any) {
    logger.error("계층 그룹 삭제 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "계층 그룹 삭제에 실패했습니다.",
      error: error.message,
    });
  }
};

// =====================================================
// 계층 레벨 관리
// =====================================================

/**
 * 레벨 추가
 */
export const addLevel = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const { groupCode } = req.params;
    const companyCode = req.user?.companyCode || "*";
    const {
      levelOrder,
      levelName,
      levelCode,
      tableName,
      valueColumn,
      labelColumn,
      parentKeyColumn,
      filterColumn,
      filterValue,
      orderColumn,
      orderDirection = "ASC",
      placeholder,
      isRequired = "Y",
      isSearchable = "N",
    } = req.body;

    // 그룹 존재 확인
    const groupCheck = await queryOne(
      `SELECT * FROM cascading_hierarchy_group WHERE group_code = $1 AND (company_code = $2 OR $2 = '*')`,
      [groupCode, companyCode]
    );

    if (!groupCheck) {
      return res.status(404).json({
        success: false,
        message: "계층 그룹을 찾을 수 없습니다.",
      });
    }

    const insertSql = `
      INSERT INTO cascading_hierarchy_level (
        group_code, company_code, level_order, level_name, level_code,
        table_name, value_column, label_column, parent_key_column,
        filter_column, filter_value, order_column, order_direction,
        placeholder, is_required, is_searchable, is_active, created_date
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, 'Y', CURRENT_TIMESTAMP)
      RETURNING *
    `;

    const result = await queryOne(insertSql, [
      groupCode,
      groupCheck.company_code,
      levelOrder,
      levelName,
      levelCode || null,
      tableName,
      valueColumn,
      labelColumn,
      parentKeyColumn || null,
      filterColumn || null,
      filterValue || null,
      orderColumn || null,
      orderDirection,
      placeholder || `${levelName} 선택`,
      isRequired,
      isSearchable,
    ]);

    logger.info("계층 레벨 추가", { groupCode, levelOrder, levelName });

    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 updateLevel = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const { levelId } = req.params;
    const companyCode = req.user?.companyCode || "*";
    const {
      levelName,
      tableName,
      valueColumn,
      labelColumn,
      parentKeyColumn,
      filterColumn,
      filterValue,
      orderColumn,
      orderDirection,
      placeholder,
      isRequired,
      isSearchable,
      isActive,
    } = req.body;

    let checkSql = `SELECT * FROM cascading_hierarchy_level WHERE level_id = $1`;
    const checkParams: any[] = [Number(levelId)];

    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_hierarchy_level SET
        level_name = COALESCE($1, level_name),
        table_name = COALESCE($2, table_name),
        value_column = COALESCE($3, value_column),
        label_column = COALESCE($4, label_column),
        parent_key_column = COALESCE($5, parent_key_column),
        filter_column = COALESCE($6, filter_column),
        filter_value = COALESCE($7, filter_value),
        order_column = COALESCE($8, order_column),
        order_direction = COALESCE($9, order_direction),
        placeholder = COALESCE($10, placeholder),
        is_required = COALESCE($11, is_required),
        is_searchable = COALESCE($12, is_searchable),
        is_active = COALESCE($13, is_active),
        updated_date = CURRENT_TIMESTAMP
      WHERE level_id = $14
      RETURNING *
    `;

    const result = await queryOne(updateSql, [
      levelName,
      tableName,
      valueColumn,
      labelColumn,
      parentKeyColumn,
      filterColumn,
      filterValue,
      orderColumn,
      orderDirection,
      placeholder,
      isRequired,
      isSearchable,
      isActive,
      Number(levelId),
    ]);

    logger.info("계층 레벨 수정", { levelId });

    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 deleteLevel = async (req: AuthenticatedRequest, res: Response) => {
  try {
    const { levelId } = req.params;
    const companyCode = req.user?.companyCode || "*";

    let deleteSql = `DELETE FROM cascading_hierarchy_level WHERE level_id = $1`;
    const deleteParams: any[] = [Number(levelId)];

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

    deleteSql += ` RETURNING level_id`;

    const result = await queryOne(deleteSql, deleteParams);

    if (!result) {
      return res.status(404).json({
        success: false,
        message: "레벨을 찾을 수 없습니다.",
      });
    }

    logger.info("계층 레벨 삭제", { levelId });

    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 getLevelOptions = async (
  req: AuthenticatedRequest,
  res: Response
) => {
  try {
    const { groupCode, levelOrder } = req.params;
    const { parentValue } = req.query;
    const companyCode = req.user?.companyCode || "*";

    // 레벨 정보 조회
    let levelSql = `
      SELECT l.*, g.hierarchy_type 
      FROM cascading_hierarchy_level l
      JOIN cascading_hierarchy_group g ON l.group_code = g.group_code AND l.company_code = g.company_code
      WHERE l.group_code = $1 AND l.level_order = $2 AND l.is_active = 'Y'
    `;
    const levelParams: any[] = [groupCode, Number(levelOrder)];

    if (companyCode !== "*") {
      levelSql += ` AND l.company_code = $3`;
      levelParams.push(companyCode);
    }

    const level = await queryOne(levelSql, levelParams);

    if (!level) {
      return res.status(404).json({
        success: false,
        message: "레벨을 찾을 수 없습니다.",
      });
    }

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

    // 부모 값 필터 (레벨 2 이상)
    if (level.parent_key_column && parentValue) {
      optionsSql += ` AND ${level.parent_key_column} = $${optionsParamIndex++}`;
      optionsParams.push(parentValue);
    }

    // 고정 필터
    if (level.filter_column && level.filter_value) {
      optionsSql += ` AND ${level.filter_column} = $${optionsParamIndex++}`;
      optionsParams.push(level.filter_value);
    }

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

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

    // 정렬
    if (level.order_column) {
      optionsSql += ` ORDER BY ${level.order_column} ${level.order_direction || "ASC"}`;
    } else {
      optionsSql += ` ORDER BY ${level.label_column}`;
    }

    const optionsResult = await query(optionsSql, optionsParams);

    logger.info("계층 레벨 옵션 조회", {
      groupCode,
      levelOrder,
      parentValue,
      optionCount: optionsResult.length,
    });

    res.json({
      success: true,
      data: optionsResult,
      levelInfo: {
        levelId: level.level_id,
        levelName: level.level_name,
        placeholder: level.placeholder,
        isRequired: level.is_required,
        isSearchable: level.is_searchable,
      },
    });
  } catch (error: any) {
    logger.error("계층 레벨 옵션 조회 실패", { error: error.message });
    res.status(500).json({
      success: false,
      message: "옵션 조회에 실패했습니다.",
      error: error.message,
    });
  }
};
