<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="admin">

  <!-- ================================================================
       메뉴 관리
       ================================================================ -->

  <!-- 관리자 메뉴 목록 (WITH RECURSIVE 계층 트리) -->
  <select id="selectAdminMenuList" parameterType="map" resultType="map">
    WITH RECURSIVE V_MENU AS (
      SELECT
          1 AS LEV
          , MENU.MENU_TYPE
          , MENU.OBJID
          , MENU.PARENT_OBJ_ID
          , MENU.MENU_NAME_KOR
          , MENU.MENU_URL
          , MENU.MENU_DESC
          , MENU.SEQ
          , MENU.WRITER
          , MENU.CREATED_DATE
          , MENU.STATUS
          , MENU.COMPANY_CODE
          , MENU.LANG_KEY
          , MENU.LANG_KEY_DESC
          , MENU.MENU_ICON
          , ARRAY[MENU.OBJID] AS PATH
      FROM MENU_INFO MENU
      WHERE (MENU.PARENT_OBJ_ID IS NULL OR MENU.PARENT_OBJ_ID = '0')
      <if test="!include_inactive">
        AND MENU.STATUS = 'active'
      </if>
      <if test="menu_type != null">
        AND MENU.MENU_TYPE = #{menu_type}
      </if>
      <choose>
        <when test='!is_management_screen and menu_type != null and menu_type == "0"'>
          AND MENU.COMPANY_CODE = '*'
        </when>
        <when test='company_code == "*" and !is_management_screen'>
          AND MENU.COMPANY_CODE = '*'
        </when>
        <when test='company_code != null and company_code != "*"'>
          AND MENU.COMPANY_CODE = #{company_code}
        </when>
      </choose>
      <if test='user_id != null and user_type != null and user_type != "SUPER_ADMIN" and !is_management_screen'>
        AND EXISTS (
          SELECT 1
          FROM REL_MENU_AUTH RMA
          JOIN AUTHORITY_MASTER AM ON RMA.AUTH_OBJID = AM.OBJID
          JOIN AUTHORITY_SUB_USER ASU ON AM.OBJID = ASU.MASTER_OBJID
          WHERE RMA.MENU_OBJID = MENU.OBJID
            AND ASU.USER_ID = #{user_id}
            AND AM.STATUS = 'active'
            AND RMA.READ_YN = 'Y'
        )
      </if>
      <if test='is_management_host == false'>
        AND MENU.IS_SOLUTION_ONLY = FALSE
      </if>

      UNION ALL

      SELECT
          V.LEV + 1
          , S.MENU_TYPE
          , S.OBJID
          , S.PARENT_OBJ_ID
          , S.MENU_NAME_KOR
          , S.MENU_URL
          , S.MENU_DESC
          , S.SEQ
          , S.WRITER
          , S.CREATED_DATE
          , S.STATUS
          , S.COMPANY_CODE
          , S.LANG_KEY
          , S.LANG_KEY_DESC
          , S.MENU_ICON
          , V.PATH || S.OBJID
      FROM MENU_INFO S
      JOIN V_MENU V
          ON S.PARENT_OBJ_ID = V.OBJID
      WHERE S.OBJID != ALL(V.PATH)
      <if test="!include_inactive">
        AND S.STATUS = 'active'
      </if>
      <choose>
        <when test='user_type == "SUPER_ADMIN" and company_code == "*" and !is_management_screen'>
          AND S.COMPANY_CODE = '*'
        </when>
        <when test='company_code != null and company_code != "*"'>
          AND (S.COMPANY_CODE = #{company_code} OR S.COMPANY_CODE = '*')
        </when>
      </choose>
      <if test='user_id != null and user_type != null and user_type != "SUPER_ADMIN" and !is_management_screen'>
        AND EXISTS (
          SELECT 1
          FROM REL_MENU_AUTH RMA
          JOIN AUTHORITY_MASTER AM ON RMA.AUTH_OBJID = AM.OBJID
          JOIN AUTHORITY_SUB_USER ASU ON AM.OBJID = ASU.MASTER_OBJID
          WHERE RMA.MENU_OBJID = S.OBJID
            AND ASU.USER_ID = #{user_id}
            AND AM.STATUS = 'active'
            AND RMA.READ_YN = 'Y'
        )
      </if>
      <if test='is_management_host == false'>
        AND S.IS_SOLUTION_ONLY = FALSE
      </if>
    )
    SELECT
        V.LEV
        , CAST(V.MENU_TYPE AS TEXT) AS MENU_TYPE
        , CAST(V.OBJID AS TEXT) AS OBJID
        , CAST(V.PARENT_OBJ_ID AS TEXT) AS PARENT_OBJ_ID
        , V.MENU_NAME_KOR
        , LPAD(' ', 3 * (V.LEV - 1)) || V.MENU_NAME_KOR AS LPAD_MENU_NAME_KOR
        , COALESCE(V.MENU_URL, '') AS MENU_URL
        , COALESCE(V.MENU_DESC, '') AS MENU_DESC
        , CAST(V.SEQ AS TEXT) AS SEQ
        , V.WRITER
        , TO_CHAR(V.CREATED_DATE, 'YYYY-MM-DD') AS REGDATE
        , V.STATUS
        , V.COMPANY_CODE
        , COALESCE(V.LANG_KEY, '') AS LANG_KEY
        , COALESCE(V.LANG_KEY_DESC, '') AS LANG_KEY_DESC
        , COALESCE(V.MENU_ICON, '') AS MENU_ICON
        , COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME
        , COALESCE(MLT_NAME.LANG_TEXT, V.MENU_NAME_KOR) AS TRANSLATED_NAME
        , COALESCE(MLT_DESC.LANG_TEXT, COALESCE(V.MENU_DESC, '')) AS TRANSLATED_DESC
        , CASE UPPER(V.STATUS)
            WHEN 'ACTIVE' THEN '활성화'
            WHEN 'INACTIVE' THEN '비활성화'
            ELSE ''
          END AS STATUS_TITLE
    FROM V_MENU V
    LEFT JOIN COMPANY_MNG CM
        ON V.COMPANY_CODE = CM.COMPANY_CODE
    LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_NAME
        ON MLKM_NAME.LANG_KEY = V.LANG_KEY
    LEFT JOIN MULTI_LANG_TEXT MLT_NAME
        ON MLT_NAME.KEY_ID = MLKM_NAME.KEY_ID
       AND MLT_NAME.LANG_CODE = #{user_lang}
    LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_DESC
        ON MLKM_DESC.LANG_KEY = V.LANG_KEY_DESC
    LEFT JOIN MULTI_LANG_TEXT MLT_DESC
        ON MLT_DESC.KEY_ID = MLKM_DESC.KEY_ID
       AND MLT_DESC.LANG_CODE = #{user_lang}
    ORDER BY V.PATH, V.SEQ
  </select>

  <!-- 사용자 메뉴 목록 (사이드바용, MENU_TYPE=1) -->
  <select id="selectUserMenuList" parameterType="map" resultType="map">
    WITH RECURSIVE V_MENU AS (
      SELECT
          1 AS LEV
          , MENU.MENU_TYPE
          , MENU.OBJID
          , MENU.PARENT_OBJ_ID
          , MENU.MENU_NAME_KOR
          , MENU.MENU_URL
          , MENU.MENU_DESC
          , MENU.SEQ
          , MENU.WRITER
          , MENU.CREATED_DATE
          , MENU.STATUS
          , MENU.COMPANY_CODE
          , MENU.LANG_KEY
          , MENU.LANG_KEY_DESC
          , MENU.MENU_ICON
          , ARRAY[MENU.OBJID] AS PATH
      FROM MENU_INFO MENU
      WHERE MENU.PARENT_OBJ_ID = '0'
        AND MENU.MENU_TYPE = '1'
        AND MENU.STATUS = 'active'
      <choose>
        <when test='company_code == "*"'>
          AND MENU.COMPANY_CODE = '*'
        </when>
        <otherwise>
          AND MENU.COMPANY_CODE = #{company_code}
        </otherwise>
      </choose>
      <if test='is_management_host == false'>
        AND MENU.IS_SOLUTION_ONLY = FALSE
      </if>

      UNION ALL

      SELECT
          V.LEV + 1
          , S.MENU_TYPE
          , S.OBJID
          , S.PARENT_OBJ_ID
          , S.MENU_NAME_KOR
          , S.MENU_URL
          , S.MENU_DESC
          , S.SEQ
          , S.WRITER
          , S.CREATED_DATE
          , S.STATUS
          , S.COMPANY_CODE
          , S.LANG_KEY
          , S.LANG_KEY_DESC
          , S.MENU_ICON
          , V.PATH || S.OBJID
      FROM MENU_INFO S
      JOIN V_MENU V
          ON S.PARENT_OBJ_ID = V.OBJID
      WHERE S.OBJID != ALL(V.PATH)
        AND S.STATUS = 'active'
      <if test='is_management_host == false'>
        AND S.IS_SOLUTION_ONLY = FALSE
      </if>
    )
    SELECT
        V.LEV
        , CASE V.MENU_TYPE WHEN '0' THEN 'admin' WHEN '1' THEN 'user' ELSE '' END AS MENU_TYPE
        , CAST(V.OBJID AS TEXT) AS OBJID
        , CAST(V.PARENT_OBJ_ID AS TEXT) AS PARENT_OBJ_ID
        , V.MENU_NAME_KOR
        , LPAD(' ', 3 * (V.LEV - 1)) || V.MENU_NAME_KOR AS LPAD_MENU_NAME_KOR
        , COALESCE(V.MENU_URL, '') AS MENU_URL
        , COALESCE(V.MENU_DESC, '') AS MENU_DESC
        , CAST(V.SEQ AS TEXT) AS SEQ
        , V.WRITER
        , TO_CHAR(V.CREATED_DATE, 'YYYY-MM-DD') AS REGDATE
        , V.STATUS
        , V.COMPANY_CODE
        , COALESCE(V.LANG_KEY, '') AS LANG_KEY
        , COALESCE(V.LANG_KEY_DESC, '') AS LANG_KEY_DESC
        , COALESCE(V.MENU_ICON, '') AS MENU_ICON
        , COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME
        , COALESCE(MLT_NAME.LANG_TEXT, V.MENU_NAME_KOR) AS TRANSLATED_NAME
        , COALESCE(MLT_DESC.LANG_TEXT, COALESCE(V.MENU_DESC, '')) AS TRANSLATED_DESC
        , CASE UPPER(V.STATUS)
            WHEN 'ACTIVE' THEN '활성화'
            WHEN 'INACTIVE' THEN '비활성화'
            ELSE ''
          END AS STATUS_TITLE
    FROM V_MENU V
    LEFT JOIN COMPANY_MNG CM
        ON V.COMPANY_CODE = CM.COMPANY_CODE
    LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_NAME
        ON MLKM_NAME.LANG_KEY = V.LANG_KEY
    LEFT JOIN MULTI_LANG_TEXT MLT_NAME
        ON MLT_NAME.KEY_ID = MLKM_NAME.KEY_ID
       AND MLT_NAME.LANG_CODE = #{user_lang}
    LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_DESC
        ON MLKM_DESC.LANG_KEY = V.LANG_KEY_DESC
    LEFT JOIN MULTI_LANG_TEXT MLT_DESC
        ON MLT_DESC.KEY_ID = MLKM_DESC.KEY_ID
       AND MLT_DESC.LANG_CODE = #{user_lang}
    ORDER BY V.PATH, V.SEQ
  </select>

  <!-- ================================================================
       사용자 메뉴 목록 (권한 그룹 기반 필터링)
       - 로그인 사용자가 속한 권한 그룹의 메뉴만 반환 (READ_YN='Y')
       - 부모 메뉴는 트리 구조 유지 위해 자동 포함
       - 관리자가 아닌 일반 사용자 전용
  ================================================================ -->
  <select id="selectUserMenuListByRole" parameterType="map" resultType="map">
    WITH RECURSIVE
      -- 1단계: 사용자의 권한 그룹에서 READ_YN='Y'인 메뉴
      PERMITTED_MENU AS (
          SELECT DISTINCT MI.*
          FROM MENU_INFO MI
          INNER JOIN AUTHORITY_SUB_MENU ASM ON ASM.MENU_OBJID = MI.OBJID
          INNER JOIN AUTHORITY_SUB_USER ASU ON ASU.MASTER_OBJID = ASM.MASTER_OBJID
          WHERE ASU.USER_ID = #{user_id}
            AND ASM.READ_YN = 'Y'
            AND MI.STATUS = 'active'
            AND MI.MENU_TYPE = '1'
      ),
      -- 2단계: 부모 체인 포함 (트리 구조 유지)
      ALLOWED_MENU AS (
          SELECT * FROM PERMITTED_MENU

          UNION

          SELECT P.*
          FROM MENU_INFO P
          INNER JOIN ALLOWED_MENU A ON A.PARENT_OBJ_ID = P.OBJID
          WHERE P.OBJID != '0'
            AND P.STATUS = 'active'
      ),
      V_MENU AS (
          SELECT
              1 AS LEV
              , MENU.MENU_TYPE
              , MENU.OBJID
              , MENU.PARENT_OBJ_ID
              , MENU.MENU_NAME_KOR
              , MENU.MENU_URL
              , MENU.MENU_DESC
              , MENU.SEQ
              , MENU.WRITER
              , MENU.CREATED_DATE
              , MENU.STATUS
              , MENU.COMPANY_CODE
              , MENU.LANG_KEY
              , MENU.LANG_KEY_DESC
              , MENU.MENU_ICON
              , ARRAY[MENU.OBJID] AS PATH
          FROM ALLOWED_MENU MENU
          WHERE MENU.PARENT_OBJ_ID = '0'
            AND MENU.MENU_TYPE = '1'
          <choose>
            <when test='company_code == "*"'>
              AND MENU.COMPANY_CODE = '*'
            </when>
            <otherwise>
              AND MENU.COMPANY_CODE = #{company_code}
            </otherwise>
          </choose>

          UNION ALL

          SELECT
              V.LEV + 1
              , S.MENU_TYPE
              , S.OBJID
              , S.PARENT_OBJ_ID
              , S.MENU_NAME_KOR
              , S.MENU_URL
              , S.MENU_DESC
              , S.SEQ
              , S.WRITER
              , S.CREATED_DATE
              , S.STATUS
              , S.COMPANY_CODE
              , S.LANG_KEY
              , S.LANG_KEY_DESC
              , S.MENU_ICON
              , V.PATH || S.OBJID
          FROM ALLOWED_MENU S
          JOIN V_MENU V
              ON S.PARENT_OBJ_ID = V.OBJID
          WHERE S.OBJID != ALL(V.PATH)
      )
    SELECT
        V.LEV
        , CASE V.MENU_TYPE WHEN '0' THEN 'admin' WHEN '1' THEN 'user' ELSE '' END AS MENU_TYPE
        , CAST(V.OBJID AS TEXT) AS OBJID
        , CAST(V.PARENT_OBJ_ID AS TEXT) AS PARENT_OBJ_ID
        , V.MENU_NAME_KOR
        , LPAD(' ', 3 * (V.LEV - 1)) || V.MENU_NAME_KOR AS LPAD_MENU_NAME_KOR
        , COALESCE(V.MENU_URL, '') AS MENU_URL
        , COALESCE(V.MENU_DESC, '') AS MENU_DESC
        , CAST(V.SEQ AS TEXT) AS SEQ
        , V.WRITER
        , TO_CHAR(V.CREATED_DATE, 'YYYY-MM-DD') AS REGDATE
        , V.STATUS
        , V.COMPANY_CODE
        , COALESCE(V.LANG_KEY, '') AS LANG_KEY
        , COALESCE(V.LANG_KEY_DESC, '') AS LANG_KEY_DESC
        , COALESCE(V.MENU_ICON, '') AS MENU_ICON
        , COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME
        , COALESCE(MLT_NAME.LANG_TEXT, V.MENU_NAME_KOR) AS TRANSLATED_NAME
        , COALESCE(MLT_DESC.LANG_TEXT, COALESCE(V.MENU_DESC, '')) AS TRANSLATED_DESC
        , CASE UPPER(V.STATUS)
            WHEN 'ACTIVE' THEN '활성화'
            WHEN 'INACTIVE' THEN '비활성화'
            ELSE ''
          END AS STATUS_TITLE
    FROM V_MENU V
    LEFT JOIN COMPANY_MNG CM
        ON V.COMPANY_CODE = CM.COMPANY_CODE
    LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_NAME
        ON MLKM_NAME.LANG_KEY = V.LANG_KEY
    LEFT JOIN MULTI_LANG_TEXT MLT_NAME
        ON MLT_NAME.KEY_ID = MLKM_NAME.KEY_ID
       AND MLT_NAME.LANG_CODE = #{user_lang}
    LEFT JOIN MULTI_LANG_KEY_MASTER MLKM_DESC
        ON MLKM_DESC.LANG_KEY = V.LANG_KEY_DESC
    LEFT JOIN MULTI_LANG_TEXT MLT_DESC
        ON MLT_DESC.KEY_ID = MLKM_DESC.KEY_ID
       AND MLT_DESC.LANG_CODE = #{user_lang}
    ORDER BY V.PATH, V.SEQ
  </select>

  <!-- POP 메뉴: 부모 메뉴 조회 -->
  <select id="selectPopParentMenu" parameterType="map" resultType="map">
    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%')
    <choose>
      <when test='user_type == "SUPER_ADMIN" and company_code == "*"'>
        AND COMPANY_CODE = '*'
      </when>
      <otherwise>
        AND COMPANY_CODE = #{company_code}
      </otherwise>
    </choose>
    ORDER BY SEQ
    LIMIT 1
  </select>

  <!-- POP 메뉴: 자식 메뉴 조회 -->
  <select id="selectPopChildMenus" parameterType="map" resultType="map">
    SELECT
        OBJID
        , MENU_NAME_KOR
        , MENU_URL
        , MENU_DESC
        , SEQ
        , COMPANY_CODE
        , STATUS
    FROM MENU_INFO
    WHERE PARENT_OBJ_ID = #{parent_objid}
      AND STATUS = 'active'
      AND COMPANY_CODE = #{parent_company_code}
    ORDER BY SEQ
  </select>

  <!-- 메뉴 단건 조회 -->
  <select id="selectMenuById" parameterType="map" resultType="map">
    SELECT
        M.*
        , C.COMPANY_NAME
    FROM MENU_INFO M
    LEFT JOIN COMPANY_MNG C
        ON M.COMPANY_CODE = C.COMPANY_CODE
    WHERE M.OBJID = #{menu_id}
  </select>

  <!-- 메뉴 등록 -->
  <insert id="insertMenu" parameterType="map">
    INSERT INTO MENU_INFO (
        OBJID
        , MENU_TYPE
        , PARENT_OBJ_ID
        , MENU_NAME_KOR
        , MENU_URL
        , MENU_DESC
        , SEQ
        , WRITER
        , CREATED_DATE
        , STATUS
        , COMPANY_CODE
        , LANG_KEY
        , LANG_KEY_DESC
        , MENU_ICON
        , USER_ID
    ) VALUES (
        #{objid}
        , #{menu_type}
        , #{parent_obj_id}
        , #{menu_name_kor}
        , #{menu_url}
        , #{menu_desc}
        , #{seq}
        , #{writer}
        , NOW()
        , COALESCE(#{status}, 'active')
        , #{company_code}
        , #{lang_key}
        , #{lang_key_desc}
        , #{menu_icon}
        , #{user_id}
    )
  </insert>

  <!-- 메뉴 수정 -->
  <update id="updateMenu" parameterType="map">
    UPDATE MENU_INFO
    SET
        MENU_NAME_KOR = #{menu_name_kor}
        , MENU_URL = #{menu_url}
        , MENU_DESC = #{menu_desc}
        , SEQ = #{seq}
        , STATUS = #{status}
        , LANG_KEY = #{lang_key}
        , LANG_KEY_DESC = #{lang_key_desc}
        , MENU_ICON = #{menu_icon}
        <if test="parent_obj_id != null">, PARENT_OBJ_ID = #{parent_obj_id}</if>
        <if test="menu_type != null">, MENU_TYPE = #{menu_type}</if>
        <if test="company_code != null">, COMPANY_CODE = #{company_code}</if>
    WHERE OBJID = #{menu_id}
  </update>

  <!-- 메뉴 삭제 -->
  <delete id="deleteMenu" parameterType="map">
    DELETE FROM MENU_INFO
    WHERE OBJID = #{menu_id}
  </delete>

  <!-- 메뉴 상태 토글 -->
  <update id="updateMenuStatus" parameterType="map">
    UPDATE MENU_INFO
    SET STATUS = #{status}
    WHERE OBJID = #{menu_id}
  </update>


  <!-- ================================================================
       사용자 관리
       ================================================================ -->

  <!-- 사용자 목록 조회 -->
  <select id="selectUserList" parameterType="map" resultType="map">
    SELECT
        SABUN
        , USER_ID
        , USER_NAME
        , COALESCE(USER_NAME_ENG, '') AS USER_NAME_ENG
        , COALESCE(DEPT_CODE, '') AS DEPT_CODE
        , COALESCE(DEPT_NAME, '') AS DEPT_NAME
        , COALESCE(POSITION_CODE, '') AS POSITION_CODE
        , COALESCE(POSITION_NAME, '') AS POSITION_NAME
        , COALESCE(EMAIL, '') AS EMAIL
        , COALESCE(TEL, '') AS TEL
        , COALESCE(CELL_PHONE, '') AS CELL_PHONE
        , COALESCE(USER_TYPE, '') AS USER_TYPE
        , COALESCE(USER_TYPE_NAME, '') AS USER_TYPE_NAME
        , COALESCE(TO_CHAR(CREATED_DATE, 'YYYY-MM-DD'), '') AS REG_DATE
        , STATUS
        , COMPANY_CODE
        , COALESCE(LOCALE, '') AS LOCALE
    FROM USER_INFO
    WHERE 1=1
    <if test='company_code != null and company_code != "*"'>
      AND COMPANY_CODE = #{company_code}
    </if>
    <if test="search != null and search != ''">
      AND (USER_ID ILIKE #{search}
        OR USER_NAME ILIKE #{search}
        OR DEPT_NAME ILIKE #{search}
        OR POSITION_NAME ILIKE #{search}
        OR USER_TYPE_NAME ILIKE #{search}
        OR SABUN ILIKE #{search}
        OR EMAIL ILIKE #{search}
        OR TEL ILIKE #{search}
        OR CELL_PHONE ILIKE #{search})
    </if>
    <if test="status != null and status != ''">
      AND STATUS = #{status}
    </if>
    <if test="dept_code != null and dept_code != ''">
      AND DEPT_CODE = #{dept_code}
    </if>
    ORDER BY CREATED_DATE DESC, USER_NAME ASC
    <include refid="common.pagination"/>
  </select>

  <!-- 사용자 수 조회 -->
  <select id="selectUserCount" parameterType="map" resultType="int">
    SELECT COUNT(*)
    FROM USER_INFO
    WHERE 1=1
    <if test='company_code != null and company_code != "*"'>
      AND COMPANY_CODE = #{company_code}
    </if>
    <if test="search != null and search != ''">
      AND (USER_ID ILIKE #{search}
        OR USER_NAME ILIKE #{search}
        OR DEPT_NAME ILIKE #{search}
        OR POSITION_NAME ILIKE #{search}
        OR USER_TYPE_NAME ILIKE #{search}
        OR SABUN ILIKE #{search}
        OR EMAIL ILIKE #{search}
        OR TEL ILIKE #{search}
        OR CELL_PHONE ILIKE #{search})
    </if>
    <if test="status != null and status != ''">
      AND STATUS = #{status}
    </if>
    <if test="dept_code != null and dept_code != ''">
      AND DEPT_CODE = #{dept_code}
    </if>
  </select>

  <!-- 사용자 단건 조회 -->
  <select id="selectUserById" parameterType="map" resultType="map">
    SELECT
        SABUN
        , USER_ID
        , USER_NAME
        , USER_NAME_ENG
        , USER_NAME_CN
        , DEPT_CODE
        , DEPT_NAME
        , POSITION_CODE
        , POSITION_NAME
        , EMAIL
        , TEL
        , CELL_PHONE
        , USER_TYPE
        , USER_TYPE_NAME
        , PARTNER_OBJID
        , COMPANY_CODE
        , LOCALE
        , STATUS
        , TO_CHAR(CREATED_DATE, 'YYYY-MM-DD') AS REG_DATE
    FROM USER_INFO
    WHERE USER_ID = #{user_id}
  </select>

  <!-- 사용자 변경이력 조회 -->
  <select id="selectUserHistory" parameterType="map" resultType="map">
    SELECT *
    FROM USER_CHANGE_HISTORY
    WHERE USER_ID = #{user_id}
    ORDER BY CHANGED_AT DESC
    <include refid="common.pagination"/>
  </select>

  <!-- 사용자 등록 -->
  <insert id="insertUser" parameterType="map">
    INSERT INTO USER_INFO (
        USER_ID
        , USER_PASSWORD
        , USER_NAME
        , USER_NAME_ENG
        , DEPT_CODE
        , DEPT_NAME
        , POSITION_CODE
        , POSITION_NAME
        , EMAIL
        , TEL
        , CELL_PHONE
        , USER_TYPE
        , USER_TYPE_NAME
        , COMPANY_CODE
        , LOCALE
        , STATUS
        , CREATED_DATE
    ) VALUES (
        #{user_id}
        , #{user_password}
        , #{user_name}
        , #{user_name_eng}
        , #{dept_code}
        , #{dept_name}
        , #{position_code}
        , #{position_name}
        , #{email}
        , #{tel}
        , #{cell_phone}
        , #{user_type}
        , #{user_type_name}
        , #{company_code}
        , #{locale}
        , COALESCE(#{status}, 'active')
        , NOW()
    )
  </insert>

  <!-- 사용자 수정 -->
  <update id="updateUser" parameterType="map">
    UPDATE USER_INFO
    SET
        USER_NAME = #{user_name}
        , USER_NAME_ENG = #{user_name_eng}
        , DEPT_CODE = #{dept_code}
        , DEPT_NAME = #{dept_name}
        , POSITION_CODE = #{position_code}
        , POSITION_NAME = #{position_name}
        , EMAIL = #{email}
        , TEL = #{tel}
        , CELL_PHONE = #{cell_phone}
        , USER_TYPE = #{user_type}
        , USER_TYPE_NAME = #{user_type_name}
    WHERE USER_ID = #{user_id}
  </update>

  <!-- 사용자 상태 변경 -->
  <update id="updateUserStatus" parameterType="map">
    UPDATE USER_INFO
    SET STATUS = #{status}
    WHERE USER_ID = #{user_id}
  </update>

  <!-- 비밀번호 초기화 -->
  <update id="updateUserPassword" parameterType="map">
    UPDATE USER_INFO
    SET USER_PASSWORD = #{user_password}
    WHERE USER_ID = #{user_id}
  </update>

  <!-- 사용자 로케일 조회 -->
  <select id="selectUserLocale" parameterType="map" resultType="map">
    SELECT
        LOCALE
    FROM USER_INFO
    WHERE USER_ID = #{user_id}
  </select>

  <!-- 사용자 로케일 저장 -->
  <update id="updateUserLocale" parameterType="map">
    UPDATE USER_INFO
    SET LOCALE = #{locale}
    WHERE USER_ID = #{user_id}
  </update>

  <!-- ================================================================
       부서 관리
       ================================================================ -->

  <select id="selectDepartmentList" parameterType="map" resultType="map">
    SELECT
        DEPT_CODE
        , PARENT_DEPT_CODE
        , DEPT_NAME
        , LOCATION
        , CASE WHEN CREATED_DATE IS NOT NULL THEN TO_CHAR(CREATED_DATE, 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"') ELSE NULL END AS CREATED_DATE
        , STATUS
        , COMPANY_CODE
        , COMPANY_NAME
    FROM DEPT_INFO
    WHERE 1=1
    <include refid="common.companyCodeFilter"/>
    <if test="status != null and status != ''">
      AND STATUS = #{status}
    </if>
    <if test="search != null and search != ''">
      AND (DEPT_NAME ILIKE '%' || #{search} || '%'
        OR DEPT_CODE ILIKE '%' || #{search} || '%')
    </if>
    ORDER BY PARENT_DEPT_CODE ASC NULLS FIRST, DEPT_NAME ASC
  </select>

  <!-- ================================================================
       회사 관리
       ================================================================ -->

  <select id="selectCompanyList" parameterType="map" resultType="map">
    SELECT
        COMPANY_CODE
        , COMPANY_NAME
        , BUSINESS_REGISTRATION_NUMBER
        , REPRESENTATIVE_NAME
        , REPRESENTATIVE_PHONE
        , EMAIL
        , WEBSITE
        , ADDRESS
        , STATUS
        , WRITER
        , CREATED_DATE AS REGDATE
    FROM COMPANY_MNG
    WHERE (STATUS = 'active' OR STATUS IS NULL)
    ORDER BY COMPANY_NAME ASC
  </select>

  <select id="selectCompanyByCode" parameterType="map" resultType="map">
    SELECT
        COMPANY_CODE
        , COMPANY_NAME
        , STATUS
        , WRITER
        , CREATED_DATE AS REGDATE
    FROM COMPANY_MNG
    WHERE (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
  </select>

  <insert id="insertCompany" parameterType="map">
    INSERT INTO COMPANY_MNG (
        COMPANY_CODE
        , COMPANY_NAME
        , BUSINESS_REGISTRATION_NUMBER
        , REPRESENTATIVE_NAME
        , REPRESENTATIVE_PHONE
        , EMAIL
        , WEBSITE
        , ADDRESS
        , STATUS
        , WRITER
        , CREATED_DATE
    ) VALUES (
        #{company_code}
        , #{company_name}
        , #{business_registration_number}
        , #{representative_name}
        , #{representative_phone}
        , #{email}
        , #{website}
        , #{address}
        , COALESCE(#{status}, 'active')
        , #{writer}
        , NOW()
    )
  </insert>

  <update id="updateCompany" parameterType="map">
    UPDATE COMPANY_MNG
    SET
        COMPANY_NAME = #{company_name}
        , BUSINESS_REGISTRATION_NUMBER = #{business_registration_number}
        , REPRESENTATIVE_NAME = #{representative_name}
        , REPRESENTATIVE_PHONE = #{representative_phone}
        , EMAIL = #{email}
        , WEBSITE = #{website}
        , ADDRESS = #{address}
        , STATUS = #{status}
    WHERE (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
  </update>

  <delete id="deleteCompany" parameterType="map">
    UPDATE COMPANY_MNG
    SET STATUS = 'inactive'
    WHERE (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
  </delete>

  <!-- ================================================================
       user_dept 관리
       ================================================================ -->

  <!-- 사용자 부서 목록 조회 (메인 + 겸직) -->
  <select id="selectUserDeptList" parameterType="map" resultType="map">
    SELECT *
    FROM USER_DEPT
    WHERE USER_ID = #{user_id}
    ORDER BY IS_PRIMARY DESC, CREATED_DATE ASC
  </select>

  <!-- 사용자 부서 UPSERT -->
  <insert id="upsertUserDept" parameterType="map">
    INSERT INTO USER_DEPT (
        USER_ID
        , DEPT_CODE
        , IS_PRIMARY
        , DEPT_NAME
        , USER_NAME
        , POSITION_NAME
        , COMPANY_CODE
        , CREATED_DATE
        , UPDATED_DATE
    ) VALUES (
        #{user_id}
        , #{dept_code}
        , #{is_primary}
        , #{dept_name}
        , #{user_name}
        , #{position_name}
        , #{company_code}
        , NOW()
        , NOW()
    )
    ON CONFLICT (USER_ID, DEPT_CODE) DO UPDATE
    SET
        IS_PRIMARY = #{is_primary}
        , DEPT_NAME = #{dept_name}
        , USER_NAME = #{user_name}
        , POSITION_NAME = #{position_name}
        , COMPANY_CODE = #{company_code}
        , UPDATED_DATE = NOW()
  </insert>

  <!-- 기존 메인 부서를 겸직으로 전환 -->
  <update id="updateUserDeptNotPrimary" parameterType="map">
    UPDATE USER_DEPT
    SET
        IS_PRIMARY = FALSE
        , UPDATED_DATE = NOW()
    WHERE USER_ID = #{user_id}
      AND DEPT_CODE = #{dept_code}
  </update>

  <!-- 겸직 부서 전체 삭제 (메인 제외) -->
  <delete id="deleteUserDeptSub" parameterType="map">
    DELETE FROM USER_DEPT
    WHERE USER_ID = #{user_id}
      AND IS_PRIMARY = FALSE
  </delete>

  <!-- 사용자 정보 동적 수정 (saveUserWithDept 전용) -->
  <update id="updateUserForDept" parameterType="map">
    UPDATE USER_INFO
    <set>
      <if test="user_name != null">USER_NAME = #{user_name},</if>
      <if test="user_name_eng != null">USER_NAME_ENG = #{user_name_eng},</if>
      <if test="email != null">EMAIL = #{email},</if>
      <if test="tel != null">TEL = #{tel},</if>
      <if test="cell_phone != null">CELL_PHONE = #{cell_phone},</if>
      <if test="sabun != null">SABUN = #{sabun},</if>
      <if test="user_type != null">USER_TYPE = #{user_type},</if>
      <if test="user_type_name != null">USER_TYPE_NAME = #{user_type_name},</if>
      <if test="status != null">STATUS = #{status},</if>
      <if test="locale != null">LOCALE = #{locale},</if>
      <if test="dept_code != null">DEPT_CODE = #{dept_code},</if>
      <if test="dept_name != null">DEPT_NAME = #{dept_name},</if>
      <if test="position_code != null">POSITION_CODE = #{position_code},</if>
      <if test="position_name != null">POSITION_NAME = #{position_name},</if>
      <if test="company_code != null">COMPANY_CODE = #{company_code},</if>
      <if test="user_password != null">USER_PASSWORD = #{user_password},</if>
      USER_ID = #{user_id}
    </set>
    WHERE USER_ID = #{user_id}
  </update>

  <!-- ================================================================
       테이블 스키마 조회
       ================================================================ -->

  <select id="selectTableSchema" parameterType="map" resultType="map">
    SELECT
        COLUMN_NAME
        , DATA_TYPE
        , IS_NULLABLE
        , COLUMN_DEFAULT
        , ORDINAL_POSITION
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_SCHEMA = 'public'
      AND TABLE_NAME = #{table_name}
    ORDER BY ORDINAL_POSITION
  </select>

  <!-- ================================================================
       로케일 검증
       ================================================================ -->

  <select id="selectValidLocale" parameterType="map" resultType="map">
    SELECT
        LANG_CODE
    FROM LANGUAGE_MASTER
    WHERE LANG_CODE = #{locale}
      AND IS_ACTIVE = 'Y'
  </select>

</mapper>
