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

export class AdminService {
  /**
   * 관리자 메뉴 목록 조회 (회사별 필터링 적용)
   */
  static async getAdminMenuList(paramMap: any): Promise<any[]> {
    try {
      logger.debug("AdminService.getAdminMenuList 시작");

      const {
        userId,
        userCompanyCode,
        userType,
        userLang = "ko",
        menuType,
      } = paramMap;

      // menuType에 따른 WHERE 조건 생성
      const menuTypeCondition =
        menuType !== undefined
          ? `MENU.MENU_TYPE = ${parseInt(menuType)}`
          : "1 = 1";

      // 메뉴 관리 화면인지 좌측 사이드바인지 구분
      // includeInactive가 true거나 menuType이 undefined면 메뉴 관리 화면
      const includeInactive = paramMap.includeInactive === true;
      const isManagementScreen = includeInactive || menuType === undefined;
      // 메뉴 관리 화면: 모든 상태의 메뉴 표시, 좌측 사이드바: active만 표시
      const statusCondition = isManagementScreen
        ? "1 = 1"
        : "MENU.STATUS = 'active'";
      const subStatusCondition = isManagementScreen
        ? "1 = 1"
        : "MENU_SUB.STATUS = 'active'";

      // 1. 권한 그룹 기반 필터링 (좌측 사이드바인 경우만)
      let authFilter = "";
      let unionFilter = ""; // UNION ALL의 하위 메뉴 필터
      let queryParams: any[] = [userLang];
      let paramIndex = 2;

      if (
        menuType !== undefined &&
        userType !== "SUPER_ADMIN" &&
        !isManagementScreen
      ) {
        // 좌측 사이드바 + SUPER_ADMIN이 아닌 경우만 권한 체크
        const userRoleGroups = await query<any>(
          `
          SELECT DISTINCT am.objid AS role_objid, am.auth_name
          FROM authority_master am
          JOIN authority_sub_user asu ON am.objid = asu.master_objid
          WHERE asu.user_id = $1
            AND am.status = 'active'
          `,
          [userId]
        );

        logger.info(
          `✅ 사용자 ${userId}가 속한 권한 그룹: ${userRoleGroups.length}개`,
          {
            roleGroups: userRoleGroups.map((rg: any) => rg.auth_name),
          }
        );

        // [임시 비활성화] 메뉴 권한 그룹 체크 - 모든 사용자에게 전체 메뉴 표시
        // TODO: 권한 체크 다시 활성화 필요
        logger.info(
          `⚠️ [임시 비활성화] 권한 그룹 체크 스킵 - 사용자 ${userId}(${userType})에게 전체 메뉴 표시`
        );

        /* [원본 코드 - 권한 그룹 체크]
        if (userType === "COMPANY_ADMIN") {
          // 회사 관리자: 권한 그룹 기반 필터링 적용
          if (userRoleGroups.length > 0) {
            const roleObjids = userRoleGroups.map((rg: any) => rg.role_objid);
            // 회사 관리자도 권한 그룹 설정에 따라 메뉴 필터링
            authFilter = `
              AND MENU.COMPANY_CODE IN ($${paramIndex}, '*')
              AND EXISTS (
                SELECT 1
                FROM rel_menu_auth rma
                WHERE rma.menu_objid = MENU.OBJID
                  AND rma.auth_objid = ANY($${paramIndex + 1})
                  AND rma.read_yn = 'Y'
              )
            `;
            queryParams.push(userCompanyCode);
            paramIndex++;

            // 하위 메뉴도 권한 체크
            unionFilter = `
              AND MENU_SUB.COMPANY_CODE IN ($${paramIndex - 1}, '*')
              AND EXISTS (
                SELECT 1
                FROM rel_menu_auth rma
                WHERE rma.menu_objid = MENU_SUB.OBJID
                  AND rma.auth_objid = ANY($${paramIndex})
                  AND rma.read_yn = 'Y'
              )
            `;
            queryParams.push(roleObjids);
            paramIndex++;
            logger.info(
              `✅ 회사 관리자: 권한 있는 메뉴만 (${roleObjids.length}개 그룹)`
            );
          } else {
            // 권한 그룹이 없는 회사 관리자: 메뉴 없음
            logger.warn(
              `⚠️ 회사 관리자 ${userId}는 권한 그룹이 없어 메뉴가 표시되지 않습니다.`
            );
            return [];
          }
        } else {
          // 일반 사용자: 권한 그룹 필수
          if (userRoleGroups.length > 0) {
            const roleObjids = userRoleGroups.map((rg: any) => rg.role_objid);
            authFilter = `
              AND EXISTS (
                SELECT 1
                FROM rel_menu_auth rma
                WHERE rma.menu_objid = MENU.OBJID
                  AND rma.auth_objid = ANY($${paramIndex})
                  AND rma.read_yn = 'Y'
              )
            `;
            unionFilter = `
              AND EXISTS (
                SELECT 1
                FROM rel_menu_auth rma
                WHERE rma.menu_objid = MENU_SUB.OBJID
                  AND rma.auth_objid = ANY($${paramIndex})
                  AND rma.read_yn = 'Y'
              )
            `;
            queryParams.push(roleObjids);
            paramIndex++;
            logger.info(
              `✅ 일반 사용자: 권한 있는 메뉴만 (${roleObjids.length}개 그룹)`
            );
          } else {
            // 권한 그룹이 없는 일반 사용자: 메뉴 없음
            logger.warn(
              `⚠️ 사용자 ${userId}는 권한 그룹이 없어 메뉴가 표시되지 않습니다.`
            );
            return [];
          }
        }
        */
      } else if (
        menuType !== undefined &&
        userType === "SUPER_ADMIN" &&
        !isManagementScreen
      ) {
        // 좌측 사이드바 + SUPER_ADMIN: 권한 그룹 체크 없이 모든 공통 메뉴 표시
        logger.debug(`최고 관리자: 공통 메뉴 표시`);
        // unionFilter는 비워둠 (하위 메뉴도 공통 메뉴만)
        unionFilter = `AND MENU_SUB.COMPANY_CODE = '*'`;
      }

      // 2. 회사별 필터링 조건 생성
      let companyFilter = "";

      // SUPER_ADMIN과 COMPANY_ADMIN 구분
      if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
        // SUPER_ADMIN
        if (isManagementScreen) {
          // 메뉴 관리 화면: 모든 메뉴
          logger.debug("메뉴 관리 화면 (SUPER_ADMIN): 모든 메뉴 표시");
          companyFilter = "";
        } else {
          // 좌측 사이드바: 공통 메뉴만 (company_code = '*')
          logger.debug("좌측 사이드바 (SUPER_ADMIN): 공통 메뉴만 표시");
          companyFilter = `AND MENU.COMPANY_CODE = '*'`;
        }
      } else if (isManagementScreen) {
        // 메뉴 관리 화면: 회사별 필터링
        if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
          // 최고 관리자: 모든 메뉴 (공통 + 모든 회사)
          logger.debug("메뉴 관리 화면 (SUPER_ADMIN): 모든 메뉴 표시");
          companyFilter = "";
        } else {
          // 회사 관리자: 자기 회사 메뉴만 (공통 메뉴 제외)
          logger.info(
            `✅ 메뉴 관리 화면 (${userType}): 회사 ${userCompanyCode} 메뉴만 표시 (공통 메뉴 제외)`
          );
          companyFilter = `AND MENU.COMPANY_CODE = $${paramIndex}`;
          queryParams.push(userCompanyCode);
          paramIndex++;

          // 하위 메뉴에도 회사 필터링 적용 (공통 메뉴 제외)
          if (unionFilter === "") {
            unionFilter = `AND MENU_SUB.COMPANY_CODE = $${paramIndex - 1}`;
          }
        }
      } else if (menuType !== undefined) {
        // 좌측 사이드바: authFilter에서 이미 회사 필터링 포함
        // 회사 관리자는 좌측 사이드바에서도 자기 회사 메뉴 조회 가능
        logger.info(
          `✅ 좌측 사이드바: 회사 ${userCompanyCode} 메뉴 표시 (${userType})`
        );
        // companyFilter는 authFilter에서 이미 처리됨
      }

      // 기존 Java의 selectAdminMenuList 쿼리를 Raw Query로 포팅
      // WITH RECURSIVE 쿼리 구현
      const menuList = await query<any>(
        `
        WITH RECURSIVE v_menu(
          LEVEL,
          MENU_TYPE,
          OBJID,
          PARENT_OBJ_ID,
          MENU_NAME_KOR,
          MENU_URL,
          MENU_DESC,
          SEQ,
          WRITER,
          REGDATE,
          STATUS,
          SYSTEM_NAME,
          COMPANY_CODE,
          LANG_KEY,
          LANG_KEY_DESC,
          PATH,
          CYCLE,
          TRANSLATED_NAME,
          TRANSLATED_DESC,
          MENU_ICON
        ) AS (
          SELECT 
            1 AS LEVEL,
            MENU.MENU_TYPE, 
            MENU.OBJID::numeric,
            MENU.PARENT_OBJ_ID,
            MENU.MENU_NAME_KOR,
            MENU.MENU_URL,
            MENU.MENU_DESC,
            MENU.SEQ,
            MENU.WRITER,
            MENU.REGDATE,
            MENU.STATUS,
            MENU.SYSTEM_NAME,
            MENU.COMPANY_CODE,
            MENU.LANG_KEY,
            MENU.LANG_KEY_DESC,
            ARRAY [MENU.OBJID],
            FALSE,
            -- 번역된 메뉴명 (우선순위: 회사별 번역 > 공통 번역 > 기본명)
            COALESCE(
              (SELECT MLT.lang_text 
               FROM MULTI_LANG_KEY_MASTER MLKM 
               JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id 
               WHERE MLKM.lang_key = MENU.LANG_KEY 
                 AND (MLKM.company_code = MENU.COMPANY_CODE OR (MENU.COMPANY_CODE IS NULL AND MLKM.company_code = '*'))
                 AND MLT.lang_code = $1
               LIMIT 1),
              (SELECT MLT.lang_text 
               FROM MULTI_LANG_KEY_MASTER MLKM 
               JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id 
               WHERE MLKM.lang_key = MENU.LANG_KEY 
                 AND MLKM.company_code = '*' 
                 AND MLT.lang_code = $1
               LIMIT 1),
              MENU.MENU_NAME_KOR
            ),
            -- 번역된 설명 (우선순위: 회사별 번역 > 공통 번역 > 기본명)
            COALESCE(
              (SELECT MLT.lang_text 
               FROM MULTI_LANG_KEY_MASTER MLKM 
               JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id 
               WHERE MLKM.lang_key = MENU.LANG_KEY_DESC 
                 AND (MLKM.company_code = MENU.COMPANY_CODE OR (MENU.COMPANY_CODE IS NULL AND MLKM.company_code = '*'))
                 AND MLT.lang_code = $1
               LIMIT 1),
              (SELECT MLT.lang_text 
               FROM MULTI_LANG_KEY_MASTER MLKM 
               JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id 
               WHERE MLKM.lang_key = MENU.LANG_KEY_DESC 
                 AND MLKM.company_code = '*' 
                 AND MLT.lang_code = $1
               LIMIT 1),
              MENU.MENU_DESC
            ),
            MENU.MENU_ICON
          FROM MENU_INFO MENU
          WHERE ${menuTypeCondition}
            AND ${statusCondition}
            ${companyFilter}
            ${authFilter}
            AND NOT EXISTS (
              SELECT 1 FROM MENU_INFO parent_menu 
              WHERE parent_menu.OBJID = MENU.PARENT_OBJ_ID
            )
          
          UNION ALL
          
          SELECT 
            V_MENU.LEVEL + 1,
            MENU_SUB.MENU_TYPE, 
            MENU_SUB.OBJID,
            MENU_SUB.PARENT_OBJ_ID,
            MENU_SUB.MENU_NAME_KOR,
            MENU_SUB.MENU_URL,
            MENU_SUB.MENU_DESC,
            MENU_SUB.SEQ,
            MENU_SUB.WRITER,
            MENU_SUB.REGDATE,
            MENU_SUB.STATUS,
            MENU_SUB.SYSTEM_NAME,
            MENU_SUB.COMPANY_CODE,
            MENU_SUB.LANG_KEY,
            MENU_SUB.LANG_KEY_DESC,
            PATH || MENU_SUB.SEQ::numeric,
            MENU_SUB.OBJID = ANY(PATH),
            -- 번역된 메뉴명 (우선순위: 회사별 번역 > 공통 번역 > 기본명)
            COALESCE(
              (SELECT MLT.lang_text 
               FROM MULTI_LANG_KEY_MASTER MLKM 
               JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id 
               WHERE MLKM.lang_key = MENU_SUB.LANG_KEY 
                 AND (MLKM.company_code = MENU_SUB.COMPANY_CODE OR (MENU_SUB.COMPANY_CODE IS NULL AND MLKM.company_code = '*'))
                 AND MLT.lang_code = $1
               LIMIT 1),
              (SELECT MLT.lang_text 
               FROM MULTI_LANG_KEY_MASTER MLKM 
               JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id 
               WHERE MLKM.lang_key = MENU_SUB.LANG_KEY 
                 AND MLKM.company_code = '*' 
                 AND MLT.lang_code = $1
               LIMIT 1),
              MENU_SUB.MENU_NAME_KOR
            ),
            -- 번역된 설명 (우선순위: 회사별 번역 > 공통 번역 > 기본명)
            COALESCE(
              (SELECT MLT.lang_text 
               FROM MULTI_LANG_KEY_MASTER MLKM 
               JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id 
               WHERE MLKM.lang_key = MENU_SUB.LANG_KEY_DESC 
                 AND (MLKM.company_code = MENU_SUB.COMPANY_CODE OR (MENU_SUB.COMPANY_CODE IS NULL AND MLKM.company_code = '*'))
                 AND MLT.lang_code = $1
               LIMIT 1),
              (SELECT MLT.lang_text 
               FROM MULTI_LANG_KEY_MASTER MLKM 
               JOIN MULTI_LANG_TEXT MLT ON MLKM.key_id = MLT.key_id 
               WHERE MLKM.lang_key = MENU_SUB.LANG_KEY_DESC 
                 AND MLKM.company_code = '*' 
                 AND MLT.lang_code = $1
               LIMIT 1),
              MENU_SUB.MENU_DESC
            ),
            MENU_SUB.MENU_ICON
          FROM MENU_INFO MENU_SUB
          JOIN V_MENU ON MENU_SUB.PARENT_OBJ_ID = V_MENU.OBJID
          WHERE MENU_SUB.OBJID != ANY(V_MENU.PATH)
            AND ${subStatusCondition}
            ${unionFilter}
        )
        SELECT 
          LEVEL AS LEV,
          CAST(MENU_TYPE AS TEXT) AS MENU_TYPE,
          A.OBJID,
          A.PARENT_OBJ_ID,
          A.MENU_NAME_KOR,
          LPAD(' ', 3 * (LEVEL - 1)) || A.MENU_NAME_KOR AS LPAD_MENU_NAME_KOR,
          A.MENU_URL,
          A.MENU_DESC,
          A.SEQ,
          A.WRITER,
          TO_CHAR(A.REGDATE, 'YYYY-MM-DD') AS REGDATE,
          A.STATUS,
          A.COMPANY_CODE,
          A.LANG_KEY,
          A.LANG_KEY_DESC,
          COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME,
          A.TRANSLATED_NAME,
          A.TRANSLATED_DESC,
          A.MENU_ICON,
          CASE UPPER(A.STATUS)
            WHEN 'ACTIVE' THEN '활성화'
            WHEN 'INACTIVE' THEN '비활성화'
            ELSE ''
          END AS STATUS_TITLE
        FROM v_menu A
        LEFT JOIN COMPANY_MNG CM ON A.COMPANY_CODE = CM.COMPANY_CODE
        WHERE 1 = 1
        ORDER BY PATH, SEQ
      `,
        queryParams
      );

      logger.debug(`관리자 메뉴 목록 조회 결과: ${menuList.length}개`);

      return menuList;
    } catch (error) {
      logger.error("AdminService.getAdminMenuList 오류:", error);
      throw error;
    }
  }

  /**
   * 사용자 메뉴 목록 조회 (권한 그룹 기반 필터링)
   */
  static async getUserMenuList(paramMap: any): Promise<any[]> {
    try {
      logger.debug("AdminService.getUserMenuList 시작");

      const { userId, userCompanyCode, userType, userLang = "ko" } = paramMap;

      // 1. 권한 그룹 기반 필터링 (SUPER_ADMIN은 제외)
      let authFilter = "";
      let unionFilter = "";
      let queryParams: any[] = [userLang];
      let paramIndex = 2;

      // [임시 비활성화] 메뉴 권한 그룹 체크 - 모든 사용자에게 전체 메뉴 표시
      // TODO: 권한 체크 다시 활성화 필요
      logger.debug(`getUserMenuList 권한 그룹 체크 스킵 - ${userId}(${userType})`);
      authFilter = "";
      unionFilter = "";

      /* [원본 코드 - getUserMenuList 권한 그룹 체크]
      if (userType === "SUPER_ADMIN") {
        // SUPER_ADMIN: 권한 그룹 체크 없이 해당 회사의 모든 메뉴 표시
        logger.info(`✅ 좌측 사이드바 (SUPER_ADMIN): 회사 ${userCompanyCode}의 모든 메뉴 표시`);
        authFilter = "";
        unionFilter = "";
      } else {
        // 일반 사용자 / 회사 관리자: 권한 그룹 조회 필요
        const userRoleGroups = await query<any>(
          `
          SELECT DISTINCT am.objid AS role_objid, am.auth_name
          FROM authority_master am
          JOIN authority_sub_user asu ON am.objid = asu.master_objid
          WHERE asu.user_id = $1
            AND am.status = 'active'
          `,
          [userId]
        );

        logger.info(
          `✅ 사용자 ${userId}가 속한 권한 그룹: ${userRoleGroups.length}개`,
          {
            roleGroups: userRoleGroups.map((rg: any) => rg.auth_name),
          }
        );

        if (userRoleGroups.length > 0) {
          // 권한 그룹이 있는 경우: read_yn = 'Y'인 메뉴만 필터링
          const roleObjids = userRoleGroups.map((rg: any) => rg.role_objid);
          authFilter = `
            AND EXISTS (
              SELECT 1
              FROM rel_menu_auth rma
              WHERE rma.menu_objid = MENU.OBJID
                AND rma.auth_objid = ANY($${paramIndex})
                AND rma.read_yn = 'Y'
            )
          `;
          unionFilter = `
            AND EXISTS (
              SELECT 1
              FROM rel_menu_auth rma
              WHERE rma.menu_objid = MENU_SUB.OBJID
                AND rma.auth_objid = ANY($${paramIndex})
                AND rma.read_yn = 'Y'
            )
          `;
          queryParams.push(roleObjids);
          paramIndex++;
          logger.info(
            `✅ 권한 그룹 기반 메뉴 필터링 적용: ${roleObjids.length}개 그룹`
          );
        } else {
          // 권한 그룹이 없는 경우: 메뉴 없음
          logger.warn(
            `⚠️ 사용자 ${userId}는 권한 그룹이 없어 메뉴가 표시되지 않습니다.`
          );
          return [];
        }
      }
      */

      // 2. 회사별 필터링 조건 생성
      let companyFilter = "";

      if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
        // SUPER_ADMIN: 공통 메뉴만 (company_code = '*')
        companyFilter = `AND MENU.COMPANY_CODE = '*'`;
      } else {
        // COMPANY_ADMIN/USER: 자기 회사 메뉴만
        logger.info(
          `✅ 좌측 사이드바 (COMPANY_ADMIN/USER): 회사 ${userCompanyCode} 메뉴만 표시`
        );
        companyFilter = `AND MENU.COMPANY_CODE = $${paramIndex}`;
        queryParams.push(userCompanyCode);
        paramIndex++;
      }

      // 기존 Java의 selectUserMenuList 쿼리를 Raw Query로 포팅 + 회사별 필터링
      const menuList = await query<any>(
        `
        WITH RECURSIVE v_menu(
          LEVEL,
          MENU_TYPE,
          OBJID,
          PARENT_OBJ_ID,
          MENU_NAME_KOR,
          MENU_URL,
          MENU_DESC,
          SEQ,
          WRITER,
          REGDATE,
          STATUS,
          COMPANY_CODE,
          LANG_KEY,
          LANG_KEY_DESC,
          PATH,
          CYCLE,
          MENU_ICON
        ) AS (
          SELECT 
            1 AS LEVEL,
            MENU_TYPE, 
            OBJID::numeric,
            PARENT_OBJ_ID,
            MENU_NAME_KOR,
            MENU_URL,
            MENU_DESC,
            SEQ,
            WRITER,
            REGDATE,
            STATUS,
            COMPANY_CODE,
            LANG_KEY,
            LANG_KEY_DESC,
            ARRAY [MENU.OBJID],
            FALSE,
            MENU.MENU_ICON
          FROM MENU_INFO MENU
          WHERE PARENT_OBJ_ID = 0
          AND MENU_TYPE = 1
          AND STATUS = 'active'
          ${companyFilter}
          ${authFilter}
          
          UNION ALL
          
          SELECT 
            V_MENU.LEVEL + 1,
            MENU_SUB.MENU_TYPE, 
            MENU_SUB.OBJID,
            MENU_SUB.PARENT_OBJ_ID,
            MENU_SUB.MENU_NAME_KOR,
            MENU_SUB.MENU_URL,
            MENU_SUB.MENU_DESC,
            MENU_SUB.SEQ,
            MENU_SUB.WRITER,
            MENU_SUB.REGDATE,
            MENU_SUB.STATUS,
            MENU_SUB.COMPANY_CODE,
            MENU_SUB.LANG_KEY,
            MENU_SUB.LANG_KEY_DESC,
            PATH || MENU_SUB.SEQ::numeric,
            MENU_SUB.OBJID = ANY(PATH),
            MENU_SUB.MENU_ICON
          FROM MENU_INFO MENU_SUB
          JOIN V_MENU ON MENU_SUB.PARENT_OBJ_ID = V_MENU.OBJID
          WHERE MENU_SUB.STATUS = 'active'
          ${unionFilter}
        )
        SELECT 
          LEVEL AS LEV,
          CASE MENU_TYPE
            WHEN '0' THEN 'admin'
            WHEN '1' THEN 'user'
            ELSE ''
          END AS MENU_TYPE,
          A.OBJID,
          A.PARENT_OBJ_ID,
          A.MENU_NAME_KOR,
          LPAD(' ', 3 * (LEVEL - 1)) || A.MENU_NAME_KOR AS LPAD_MENU_NAME_KOR,
          A.MENU_URL,
          A.MENU_DESC,
          A.SEQ,
          A.WRITER,
          TO_CHAR(A.REGDATE, 'YYYY-MM-DD') AS REGDATE,
          A.STATUS,
          A.COMPANY_CODE,
          A.LANG_KEY,
          A.LANG_KEY_DESC,
          A.MENU_ICON,
          COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME,
          COALESCE(MLT_NAME.lang_text, A.MENU_NAME_KOR) AS TRANSLATED_NAME,
          COALESCE(MLT_DESC.lang_text, A.MENU_DESC) AS TRANSLATED_DESC,
          CASE UPPER(A.STATUS)
            WHEN 'ACTIVE' THEN '활성화'
            WHEN 'INACTIVE' THEN '비활성화'
            ELSE ''
          END AS STATUS_TITLE
        FROM v_menu A
        LEFT JOIN COMPANY_MNG CM ON A.COMPANY_CODE = CM.COMPANY_CODE
        LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_NAME ON A.LANG_KEY = MLKM_NAME.lang_key
        LEFT JOIN MULTI_LANG_TEXT MLT_NAME ON MLKM_NAME.key_id = MLT_NAME.key_id AND MLT_NAME.lang_code = $1
        LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_DESC ON A.LANG_KEY_DESC = MLKM_DESC.lang_key
        LEFT JOIN MULTI_LANG_TEXT MLT_DESC ON MLKM_DESC.key_id = MLT_DESC.key_id AND MLT_DESC.lang_code = $1
        WHERE 1 = 1
        ORDER BY PATH, SEQ
      `,
        queryParams
      );

      logger.debug(`사용자 메뉴 목록 조회 결과: ${menuList.length}개`);

      return menuList;
    } catch (error) {
      logger.error("AdminService.getUserMenuList 오류:", error);
      throw error;
    }
  }

  /**
   * POP 메뉴 목록 조회
   * menu_name_kor에 'POP'이 포함되거나 menu_desc에 [POP] 태그가 있는 L1 메뉴의 하위 active 메뉴를 반환
   * [POP_LANDING] 태그가 있는 하위 메뉴를 landingMenu로 별도 반환
   */
  static async getPopMenuList(paramMap: any): Promise<{ parentMenu: any | null; childMenus: any[]; landingMenu: any | null }> {
    try {
      const { userCompanyCode, userType } = paramMap;
      logger.info("AdminService.getPopMenuList 시작", { userCompanyCode, userType });

      let queryParams: any[] = [];
      let paramIndex = 1;

      let companyFilter = "";
      if (userType === "SUPER_ADMIN" && userCompanyCode === "*") {
        companyFilter = `AND COMPANY_CODE = '*'`;
      } else {
        companyFilter = `AND COMPANY_CODE = $${paramIndex}`;
        queryParams.push(userCompanyCode);
        paramIndex++;
      }

      // POP L1 메뉴 조회
      const parentMenus = await query<any>(
        `SELECT OBJID, MENU_NAME_KOR, MENU_URL, MENU_DESC, SEQ, COMPANY_CODE, STATUS
         FROM MENU_INFO
         WHERE PARENT_OBJ_ID = 0
           AND MENU_TYPE = 1
           AND (
             MENU_DESC LIKE '%[POP]%'
             OR UPPER(MENU_NAME_KOR) LIKE '%POP%'
           )
           ${companyFilter}
         ORDER BY SEQ
         LIMIT 1`,
        queryParams
      );

      if (parentMenus.length === 0) {
        logger.info("POP 메뉴 없음 (L1 POP 메뉴 미발견)");
        return { parentMenu: null, childMenus: [], landingMenu: null };
      }

      const parentMenu = parentMenus[0];

      // 하위 active 메뉴 조회 (부모와 같은 company_code로 필터링)
      const childMenus = await query<any>(
        `SELECT OBJID, MENU_NAME_KOR, MENU_URL, MENU_DESC, SEQ, COMPANY_CODE, STATUS
         FROM MENU_INFO
         WHERE PARENT_OBJ_ID = $1
           AND STATUS = 'active'
           AND COMPANY_CODE = $2
         ORDER BY SEQ`,
        [parentMenu.objid, parentMenu.company_code]
      );

      // [POP_LANDING] 태그가 있는 메뉴를 랜딩 화면으로 지정
      const landingMenu = childMenus.find((m: any) => m.menu_desc?.includes("[POP_LANDING]")) || null;

      logger.info(`POP 메뉴 조회 완료: 부모=${parentMenu.menu_name_kor}, 하위=${childMenus.length}개, 랜딩=${landingMenu?.menu_name_kor || '없음'}`);

      return { parentMenu, childMenus, landingMenu };
    } catch (error) {
      logger.error("AdminService.getPopMenuList 오류:", error);
      throw error;
    }
  }

  /**
   * 메뉴 정보 조회
   */
  static async getMenuInfo(menuId: string): Promise<any> {
    try {
      logger.info(`AdminService.getMenuInfo 시작 - menuId: ${menuId}`);

      // Raw Query를 사용한 메뉴 정보 조회 (회사 정보 포함)
      const menuResult = await query<any>(
        `SELECT 
          m.*,
          c.company_name
        FROM menu_info m
        LEFT JOIN company_mng c ON m.company_code = c.company_code
        WHERE m.objid = $1::numeric`,
        [menuId]
      );

      if (!menuResult || menuResult.length === 0) {
        return null;
      }

      const menuInfo = menuResult[0];

      // 응답 형식 조정 (기존 형식과 호환성 유지)
      const result = {
        ...menuInfo,
        objid: menuInfo.objid?.toString(),
        menu_type: menuInfo.menu_type?.toString(),
        parent_obj_id: menuInfo.parent_obj_id?.toString(),
        seq: menuInfo.seq?.toString(),
        company_name: menuInfo.company_name || "미지정",
      };

      logger.info("메뉴 정보 조회 결과:", result);
      return result;
    } catch (error) {
      logger.error("AdminService.getMenuInfo 오류:", error);
      throw error;
    }
  }
}
