import { getPool } from "../database/db";
import { logger } from "../utils/logger";

/**
 * 메뉴 관련 유틸리티 서비스
 * 
 * 메뉴 스코프 기반 데이터 공유를 위한 형제 메뉴 조회 기능 제공
 */

/**
 * 메뉴의 형제 메뉴 및 자식 메뉴 OBJID 목록 조회
 * (같은 부모를 가진 메뉴들 + 자식 메뉴들)
 * 
 * 메뉴 스코프 규칙:
 * - 같은 부모를 가진 형제 메뉴들은 카테고리/채번규칙을 공유
 * - 자식 메뉴의 데이터도 부모 메뉴에서 조회 가능 (3레벨까지만 존재)
 * - 최상위 메뉴(parent_obj_id = 0)는 자기 자신만 반환
 * - 메뉴를 찾을 수 없으면 안전하게 자기 자신만 반환
 * 
 * @param menuObjid 현재 메뉴의 OBJID
 * @returns 형제 메뉴 + 자식 메뉴 OBJID 배열 (자기 자신 포함, 정렬됨)
 * 
 * @example
 * // 영업관리 (200)
 * // ├── 고객관리 (201)
 * // │   └── 고객등록 (211)
 * // ├── 계약관리 (202)
 * // └── 주문관리 (203)
 * 
 * await getSiblingMenuObjids(201);
 * // 결과: [201, 202, 203, 211] - 형제(202, 203) + 자식(211)
 */
export async function getSiblingMenuObjids(menuObjid: number): Promise<number[]> {
  const pool = getPool();

  try {
    logger.debug("메뉴 스코프 조회 시작", { menuObjid });

    // 1. 현재 메뉴 정보 조회 (부모 ID 확인)
    const currentMenuQuery = `
      SELECT parent_obj_id FROM menu_info 
      WHERE objid = $1
    `;
    const currentMenuResult = await pool.query(currentMenuQuery, [menuObjid]);

    if (currentMenuResult.rows.length === 0) {
      logger.warn("메뉴를 찾을 수 없음, 자기 자신만 반환", { menuObjid });
      return [menuObjid];
    }

    const parentObjId = Number(currentMenuResult.rows[0].parent_obj_id);

    // 2. 최상위 메뉴(parent_obj_id = 0)는 자기 자신만 반환
    if (parentObjId === 0) {
      logger.debug("최상위 메뉴, 자기 자신만 반환", { menuObjid });
      return [menuObjid];
    }

    // 3. 형제 메뉴들 조회 (같은 부모를 가진 메뉴들)
    const siblingsQuery = `
      SELECT objid FROM menu_info 
      WHERE parent_obj_id = $1
      ORDER BY objid
    `;
    const siblingsResult = await pool.query(siblingsQuery, [parentObjId]);

    const siblingObjids = siblingsResult.rows.map((row) => Number(row.objid));

    // 4. 각 형제 메뉴(자기 자신 포함)의 자식 메뉴들도 조회
    const allObjids = [...siblingObjids];
    
    for (const siblingObjid of siblingObjids) {
      const childrenQuery = `
        SELECT objid FROM menu_info 
        WHERE parent_obj_id = $1
        ORDER BY objid
      `;
      const childrenResult = await pool.query(childrenQuery, [siblingObjid]);
      const childObjids = childrenResult.rows.map((row) => Number(row.objid));
      allObjids.push(...childObjids);
    }

    // 5. 중복 제거 및 정렬
    const uniqueObjids = Array.from(new Set(allObjids)).sort((a, b) => a - b);

    logger.debug("메뉴 스코프 조회 완료", { 
      menuObjid,
      parentObjId,
      siblingCount: siblingObjids.length, 
      totalCount: uniqueObjids.length 
    });

    return uniqueObjids;
  } catch (error: any) {
    logger.error("메뉴 스코프 조회 실패", { 
      menuObjid, 
      error: error.message,
      stack: error.stack 
    });
    // 에러 발생 시 안전하게 자기 자신만 반환
    return [menuObjid];
  }
}

/**
 * 선택한 메뉴와 그 하위 메뉴들의 OBJID 조회
 * 
 * 형제 메뉴는 포함하지 않고, 선택한 메뉴와 그 자식 메뉴들만 반환합니다.
 * 채번 규칙 필터링 등 특정 메뉴 계층만 필요할 때 사용합니다.
 * 
 * @param menuObjid 메뉴 OBJID
 * @returns 선택한 메뉴 + 모든 하위 메뉴 OBJID 배열 (재귀적)
 * 
 * @example
 * // 메뉴 구조:
 * // └── 구매관리 (100)
 * //     ├── 공급업체관리 (101)
 * //     ├── 발주관리 (102)
 * //     └── 입고관리 (103)
 * //         └── 입고상세 (104)
 * 
 * await getMenuAndChildObjids(100);
 * // 결과: [100, 101, 102, 103, 104]
 */
export async function getMenuAndChildObjids(menuObjid: number): Promise<number[]> {
  const pool = getPool();

  try {
    logger.debug("메뉴 및 하위 메뉴 조회 시작", { menuObjid });

    // 재귀 CTE를 사용하여 선택한 메뉴와 모든 하위 메뉴 조회
    const query = `
      WITH RECURSIVE menu_tree AS (
        -- 시작점: 선택한 메뉴
        SELECT objid, parent_obj_id, 1 AS depth
        FROM menu_info
        WHERE objid = $1
        
        UNION ALL
        
        -- 재귀: 하위 메뉴들
        SELECT m.objid, m.parent_obj_id, mt.depth + 1
        FROM menu_info m
        INNER JOIN menu_tree mt ON m.parent_obj_id = mt.objid
        WHERE mt.depth < 10  -- 무한 루프 방지
      )
      SELECT objid FROM menu_tree ORDER BY depth, objid
    `;
    
    const result = await pool.query(query, [menuObjid]);
    const objids = result.rows.map((row) => Number(row.objid));

    logger.debug("메뉴 및 하위 메뉴 조회 완료", { 
      menuObjid,
      totalCount: objids.length,
      objids 
    });

    return objids;
  } catch (error: any) {
    logger.error("메뉴 및 하위 메뉴 조회 실패", { 
      menuObjid, 
      error: error.message,
      stack: error.stack 
    });
    // 에러 발생 시 안전하게 자기 자신만 반환
    return [menuObjid];
  }
}

/**
 * 여러 메뉴의 형제 메뉴 OBJID 합집합 조회
 * 
 * 여러 메뉴에 속한 모든 형제 메뉴를 중복 제거하여 반환
 * 
 * @param menuObjids 메뉴 OBJID 배열
 * @returns 모든 형제 메뉴 OBJID 배열 (중복 제거, 정렬됨)
 * 
 * @example
 * // 서로 다른 부모를 가진 메뉴들의 형제를 모두 조회
 * await getAllSiblingMenuObjids([201, 301]);
 * // 201의 형제: [201, 202, 203]
 * // 301의 형제: [301, 302]
 * // 결과: [201, 202, 203, 301, 302]
 */
export async function getAllSiblingMenuObjids(
  menuObjids: number[]
): Promise<number[]> {
  if (!menuObjids || menuObjids.length === 0) {
    logger.warn("getAllSiblingMenuObjids: 빈 배열 입력");
    return [];
  }

  const allSiblings = new Set<number>();

  for (const objid of menuObjids) {
    const siblings = await getSiblingMenuObjids(objid);
    siblings.forEach((s) => allSiblings.add(s));
  }

  const result = Array.from(allSiblings).sort((a, b) => a - b);

  logger.info("여러 메뉴의 형제 조회 완료", {
    inputMenus: menuObjids,
    resultCount: result.length,
    result,
  });

  return result;
}

/**
 * 메뉴 정보 조회
 * 
 * @param menuObjid 메뉴 OBJID
 * @returns 메뉴 정보 (없으면 null)
 */
export async function getMenuInfo(menuObjid: number): Promise<any | null> {
  const pool = getPool();

  try {
    const query = `
      SELECT 
        objid,
        parent_obj_id AS "parentObjId",
        menu_name_kor AS "menuNameKor",
        menu_name_eng AS "menuNameEng",
        menu_url AS "menuUrl",
        company_code AS "companyCode"
      FROM menu_info
      WHERE objid = $1
    `;
    const result = await pool.query(query, [menuObjid]);

    if (result.rows.length === 0) {
      return null;
    }

    return result.rows[0];
  } catch (error: any) {
    logger.error("메뉴 정보 조회 실패", { menuObjid, error: error.message });
    return null;
  }
}

