<?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="substitute">

  <!-- ================================================================
       USER_SUBSTITUTES — 대무자(代務者) 관리

       Spec: .omc/specs/deep-dive-user-substitute-management.md
       Plan: .omc/plans/autopilot-impl.md (T2)

       핵심:
       - 종료일 NOT NULL (무기한 금지), 시작일 NULL = 즉시
       - 활성 판정: IS_ACTIVE = TRUE AND (START_DATE IS NULL OR
                  START_DATE <= CURRENT_DATE) AND END_DATE >= CURRENT_DATE
       - 같은 쌍 + 활성 기간 겹침은 EXCLUDE 제약으로 DB 차단
       ================================================================ -->

  <!-- 활성 판정 공통 조건 -->
  <sql id="activeWindow">
    AND S.IS_ACTIVE = TRUE
    AND (S.START_DATE IS NULL OR S.START_DATE &lt;= CURRENT_DATE)
    AND S.END_DATE &gt;= CURRENT_DATE
  </sql>

  <!-- ================================================================
       조회
       ================================================================ -->

  <select id="selectSubstituteList" parameterType="map" resultType="map">
    SELECT S.SUBSTITUTE_ID
         , S.COMPANY_CODE
         , S.ORIGINAL_USER_ID
         , U1.USER_NAME AS ORIGINAL_USER_NAME
         , U1.DEPT_NAME AS ORIGINAL_DEPT_NAME
         , S.PROXY_USER_ID
         , U2.USER_NAME AS PROXY_USER_NAME
         , U2.DEPT_NAME AS PROXY_DEPT_NAME
         , S.START_DATE
         , S.END_DATE
         , S.REASON
         , S.IS_ACTIVE
         , CASE
             WHEN S.IS_ACTIVE = FALSE THEN 'inactive'
             WHEN S.END_DATE &lt; CURRENT_DATE THEN 'expired'
             WHEN S.START_DATE IS NOT NULL AND S.START_DATE &gt; CURRENT_DATE THEN 'upcoming'
             ELSE 'active'
           END AS STATUS
         , S.CREATED_BY
         , S.CREATED_DATE
         , S.UPDATED_BY
         , S.UPDATED_DATE
    FROM USER_SUBSTITUTES S
    LEFT JOIN USER_INFO U1 ON S.ORIGINAL_USER_ID = U1.USER_ID AND S.COMPANY_CODE = U1.COMPANY_CODE
    LEFT JOIN USER_INFO U2 ON S.PROXY_USER_ID    = U2.USER_ID AND S.COMPANY_CODE = U2.COMPANY_CODE
    WHERE 1=1
      AND (S.COMPANY_CODE = #{company_code} OR S.COMPANY_CODE = '*')
    <if test="original_user_id != null and original_user_id != ''">
      AND S.ORIGINAL_USER_ID = #{original_user_id}
    </if>
    <if test="proxy_user_id != null and proxy_user_id != ''">
      AND S.PROXY_USER_ID = #{proxy_user_id}
    </if>
    <choose>
      <when test='status == "active"'>
        AND S.IS_ACTIVE = TRUE
        AND (S.START_DATE IS NULL OR S.START_DATE &lt;= CURRENT_DATE)
        AND S.END_DATE &gt;= CURRENT_DATE
      </when>
      <when test='status == "upcoming"'>
        AND S.IS_ACTIVE = TRUE
        AND S.START_DATE IS NOT NULL
        AND S.START_DATE &gt; CURRENT_DATE
      </when>
      <when test='status == "expired"'>
        AND S.END_DATE &lt; CURRENT_DATE
      </when>
      <when test='status == "inactive"'>
        AND S.IS_ACTIVE = FALSE
      </when>
    </choose>
    ORDER BY
      CASE
        WHEN S.IS_ACTIVE = TRUE
         AND (S.START_DATE IS NULL OR S.START_DATE &lt;= CURRENT_DATE)
         AND S.END_DATE &gt;= CURRENT_DATE THEN 0
        WHEN S.IS_ACTIVE = TRUE AND S.START_DATE &gt; CURRENT_DATE THEN 1
        ELSE 2
      END
      , S.END_DATE DESC
      , S.CREATED_DATE DESC
    <include refid="common.pagination"/>
  </select>

  <select id="selectSubstituteListCnt" parameterType="map" resultType="int">
    SELECT COUNT(*)
    FROM USER_SUBSTITUTES S
    WHERE 1=1
      AND (S.COMPANY_CODE = #{company_code} OR S.COMPANY_CODE = '*')
    <if test="original_user_id != null and original_user_id != ''">
      AND S.ORIGINAL_USER_ID = #{original_user_id}
    </if>
    <if test="proxy_user_id != null and proxy_user_id != ''">
      AND S.PROXY_USER_ID = #{proxy_user_id}
    </if>
    <choose>
      <when test='status == "active"'>
        AND S.IS_ACTIVE = TRUE
        AND (S.START_DATE IS NULL OR S.START_DATE &lt;= CURRENT_DATE)
        AND S.END_DATE &gt;= CURRENT_DATE
      </when>
      <when test='status == "upcoming"'>
        AND S.IS_ACTIVE = TRUE
        AND S.START_DATE IS NOT NULL
        AND S.START_DATE &gt; CURRENT_DATE
      </when>
      <when test='status == "expired"'>
        AND S.END_DATE &lt; CURRENT_DATE
      </when>
      <when test='status == "inactive"'>
        AND S.IS_ACTIVE = FALSE
      </when>
    </choose>
  </select>

  <!-- ProfileModal 본인 조회: 내가 위임한 + 나를 대무 중인 -->
  <select id="selectMySubstitutes" parameterType="map" resultType="map">
    SELECT S.SUBSTITUTE_ID
         , S.COMPANY_CODE
         , S.ORIGINAL_USER_ID
         , U1.USER_NAME AS ORIGINAL_USER_NAME
         , U1.DEPT_NAME AS ORIGINAL_DEPT_NAME
         , S.PROXY_USER_ID
         , U2.USER_NAME AS PROXY_USER_NAME
         , U2.DEPT_NAME AS PROXY_DEPT_NAME
         , S.START_DATE
         , S.END_DATE
         , S.REASON
         , S.IS_ACTIVE
         , CASE
             WHEN S.ORIGINAL_USER_ID = #{user_id} THEN 'proxying_for_me'
             WHEN S.PROXY_USER_ID    = #{user_id} THEN 'my_proxies'
           END AS RELATION
         , CASE
             WHEN S.IS_ACTIVE = FALSE THEN 'inactive'
             WHEN S.END_DATE &lt; CURRENT_DATE THEN 'expired'
             WHEN S.START_DATE IS NOT NULL AND S.START_DATE &gt; CURRENT_DATE THEN 'upcoming'
             ELSE 'active'
           END AS STATUS
         , (S.END_DATE - CURRENT_DATE) AS DAYS_REMAINING
    FROM USER_SUBSTITUTES S
    LEFT JOIN USER_INFO U1 ON S.ORIGINAL_USER_ID = U1.USER_ID AND S.COMPANY_CODE = U1.COMPANY_CODE
    LEFT JOIN USER_INFO U2 ON S.PROXY_USER_ID    = U2.USER_ID AND S.COMPANY_CODE = U2.COMPANY_CODE
    WHERE (S.COMPANY_CODE = #{company_code} OR S.COMPANY_CODE = '*')
      AND (S.ORIGINAL_USER_ID = #{user_id} OR S.PROXY_USER_ID = #{user_id})
      AND S.END_DATE &gt;= CURRENT_DATE
    ORDER BY S.END_DATE ASC
  </select>

  <!-- Filter hot path: B 가 현재 대무 중인 모든 A 의 ID -->
  <select id="selectActiveOriginalUserIds" parameterType="map" resultType="string">
    SELECT S.ORIGINAL_USER_ID
    FROM USER_SUBSTITUTES S
    WHERE S.PROXY_USER_ID = #{proxy_user_id}
      AND (S.COMPANY_CODE = #{company_code} OR S.COMPANY_CODE = '*')
      <include refid="activeWindow"/>
  </select>

  <select id="selectSubstituteInfo" parameterType="map" resultType="map">
    SELECT S.*
         , U1.USER_NAME AS ORIGINAL_USER_NAME
         , U2.USER_NAME AS PROXY_USER_NAME
    FROM USER_SUBSTITUTES S
    LEFT JOIN USER_INFO U1 ON S.ORIGINAL_USER_ID = U1.USER_ID AND S.COMPANY_CODE = U1.COMPANY_CODE
    LEFT JOIN USER_INFO U2 ON S.PROXY_USER_ID    = U2.USER_ID AND S.COMPANY_CODE = U2.COMPANY_CODE
    WHERE S.SUBSTITUTE_ID = #{substitute_id}
      AND (S.COMPANY_CODE = #{company_code} OR S.COMPANY_CODE = '*')
  </select>

  <!-- 결재 어댑터: B 가 A 의 대무자로 활성 상태인지 (ApprovalService 가 호출) -->
  <select id="selectActiveProxyForLine" parameterType="map" resultType="map">
    SELECT S.*
    FROM USER_SUBSTITUTES S
    WHERE S.ORIGINAL_USER_ID = #{original_user_id}
      AND S.PROXY_USER_ID    = #{proxy_user_id}
      AND (S.COMPANY_CODE = #{company_code} OR S.COMPANY_CODE = '*')
      <include refid="activeWindow"/>
    LIMIT 1
  </select>

  <!-- ================================================================
       사전 검증
       ================================================================ -->

  <!-- 같은 쌍의 기간 겹침 사전 카운트 (EXCLUDE 제약 사전 우회용 UX) -->
  <select id="countOverlap" parameterType="map" resultType="int">
    SELECT COUNT(*)
    FROM USER_SUBSTITUTES S
    WHERE S.COMPANY_CODE = #{company_code}
      AND S.ORIGINAL_USER_ID = #{original_user_id}
      AND S.PROXY_USER_ID    = #{proxy_user_id}
      AND S.IS_ACTIVE = TRUE
      AND DATERANGE(COALESCE(S.START_DATE, CURRENT_DATE), S.END_DATE, '[]')
       &amp;&amp; DATERANGE(COALESCE(CAST(#{start_date} AS DATE), CURRENT_DATE),
                       CAST(#{end_date} AS DATE), '[]')
    <if test="exclude_substitute_id != null">
      AND S.SUBSTITUTE_ID &lt;&gt; #{exclude_substitute_id}
    </if>
  </select>

  <!-- 같은 회사에 속한 사용자인지 검증 (B3: cross-company 차단) -->
  <select id="countUserInCompany" parameterType="map" resultType="int">
    SELECT COUNT(*)
    FROM USER_INFO U
    WHERE U.USER_ID = #{user_id}
      AND U.COMPANY_CODE = #{company_code}
  </select>

  <!-- 사용자가 SUPER_ADMIN 인지 확인 (proxy_user_id 로 지정 거부 용도) -->
  <select id="countSuperAdmin" parameterType="map" resultType="int">
    SELECT COUNT(*)
    FROM USER_INFO U
    WHERE U.USER_ID = #{user_id}
      AND U.USER_TYPE = 'SUPER_ADMIN'
  </select>

  <!-- ================================================================
       변경
       ================================================================ -->

  <insert id="insertSubstitute" parameterType="map"
          useGeneratedKeys="true" keyProperty="substitute_id" keyColumn="substitute_id">
    INSERT INTO USER_SUBSTITUTES (
        COMPANY_CODE
      , ORIGINAL_USER_ID
      , PROXY_USER_ID
      , START_DATE
      , END_DATE
      , REASON
      , IS_ACTIVE
      , CREATED_BY
      , CREATED_DATE
      , UPDATED_BY
      , UPDATED_DATE
    ) VALUES (
        #{company_code}
      , #{original_user_id}
      , #{proxy_user_id}
      , CAST(#{start_date} AS DATE)
      , CAST(#{end_date} AS DATE)
      , #{reason}
      , COALESCE(#{is_active}, TRUE)
      , #{created_by}
      , NOW()
      , #{created_by}
      , NOW()
    )
  </insert>

  <update id="updateSubstitute" parameterType="map">
    UPDATE USER_SUBSTITUTES
    <set>
      <if test="proxy_user_id != null">
        PROXY_USER_ID = #{proxy_user_id},
      </if>
      <if test="start_date != null">
        START_DATE = CAST(#{start_date} AS DATE),
      </if>
      <if test="clear_start_date == true">
        START_DATE = NULL,
      </if>
      <if test="end_date != null">
        END_DATE = CAST(#{end_date} AS DATE),
      </if>
      <if test="reason != null">
        REASON = #{reason},
      </if>
      <if test="is_active != null">
        IS_ACTIVE = #{is_active},
      </if>
      UPDATED_BY = #{updated_by},
      UPDATED_DATE = NOW()
    </set>
    WHERE SUBSTITUTE_ID = #{substitute_id}
      AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
  </update>

  <delete id="deleteSubstitute" parameterType="map">
    DELETE FROM USER_SUBSTITUTES
    WHERE SUBSTITUTE_ID = #{substitute_id}
      AND (COMPANY_CODE = #{company_code} OR COMPANY_CODE = '*')
  </delete>

</mapper>
