<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.itn.itnhub.process.ProcessItemMapper">

  <!--
    processed_at/web_edited_at/created_at/updated_at을 밀리초 epoch로 내려준다
    (review_item과 동일 관례). null이면 extract(epoch from null)도 null이라 그대로 null이 내려간다.
  -->
  <sql id="columns">
    id, org_id, seq, site_name, category, board_name, post_title, url, description,
    has_attachment, prior_kogl_type, contract_docs, produced_date, published_date,
    review_major, review_minor, review_result, review_kogl_type, review_ai_type,
    review_opinion, review_note, prior_evidence,
    judged_kogl_type, judged_ai_type, final_opinion, judgment_basis, process_status,
    (extract(epoch from processed_at) * 1000)::bigint as processed_at,
    (extract(epoch from web_edited_at) * 1000)::bigint as web_edited_at,
    (extract(epoch from created_at) * 1000)::bigint as created_at,
    (extract(epoch from updated_at) * 1000)::bigint as updated_at
  </sql>

  <sql id="keywordFilter">
    <if test="keyword != null">
      and (site_name ilike concat('%', #{keyword}, '%')
        or post_title ilike concat('%', #{keyword}, '%'))
    </if>
    <!-- 열별 조건. 서로 AND로 겹쳐서 복합검색이 된다(권리확인과 동일 규칙). -->
    <if test="site != null">
      and site_name ilike concat('%', #{site}, '%')
    </if>
    <if test="board != null">
      and board_name ilike concat('%', #{board}, '%')
    </if>
    <if test="title != null">
      and post_title ilike concat('%', #{title}, '%')
    </if>
  </sql>

  <!-- status: null=전체, "DONE"=처리완료, "PENDING"=그 외(null/빈/미처리 등 처리완료가 아닌 전부). -->
  <sql id="statusFilter">
    <if test="status != null and status == 'DONE'">
      and process_status = #{doneStatus}
    </if>
    <if test="status != null and status == 'PENDING'">
      and (process_status is null or process_status = '' or process_status &lt;&gt; #{doneStatus})
    </if>
  </sql>

  <select id="findPage" resultType="kr.itn.itnhub.process.ProcessItem">
    select <include refid="columns"/>
    from process_item
    where org_id = #{orgId}
    <include refid="keywordFilter"/>
    <include refid="statusFilter"/>
    order by seq asc
    limit #{limit} offset #{offset}
  </select>

  <select id="countByOrg" resultType="int">
    select count(*)
    from process_item
    where org_id = #{orgId}
    <include refid="keywordFilter"/>
    <include refid="statusFilter"/>
  </select>

  <select id="findAllByOrg" resultType="kr.itn.itnhub.process.ProcessItem">
    select <include refid="columns"/>
    from process_item
    where org_id = #{orgId}
    order by seq asc
  </select>

  <select id="findSeqsByOrg" resultType="int">
    select seq from process_item where org_id = #{orgId}
  </select>

  <select id="findById" resultType="kr.itn.itnhub.process.ProcessItem">
    select <include refid="columns"/>
    from process_item
    where org_id = #{orgId} and id = #{id}
  </select>

  <!--
    정책(b): 조사원+권리확인 영역(site_name..prior_evidence, 계약서 유무 제외)은 재업로드마다
    항상 최신 파일값으로 덮어쓴다. 계약서 유무(contract_docs)는 웹에서 입력하는 값이라
    web_edited_at이 null일 때만(=웹에서 아직 아무도 손대지 않았을 때만) 파일값을 반영한다.
    권리처리 영역(judged_kogl_type..process_status)도 마찬가지로 web_edited_at이 null일
    때만 파일값을 반영한다 - 이미 웹에서 처리 결과를 입력한 행은 재업로드가 절대 덮어쓰지
    않는다. processed_at/web_edited_at 자체는 이 upsert가 건드리지 않는다.
  -->
  <insert id="upsertFromFile" parameterType="kr.itn.itnhub.process.ProcessItem">
    insert into process_item (
      org_id, seq, site_name, category, board_name, post_title, url, description,
      has_attachment, prior_kogl_type, contract_docs, produced_date, published_date,
      review_major, review_minor, review_result, review_kogl_type, review_ai_type,
      review_opinion, review_note, prior_evidence,
      judged_kogl_type, judged_ai_type, final_opinion, judgment_basis, process_status
    ) values (
      #{orgId}, #{seq}, #{siteName}, #{category}, #{boardName}, #{postTitle}, #{url}, #{description},
      #{hasAttachment}, #{priorKoglType}, #{contractDocs}, #{producedDate}, #{publishedDate},
      #{reviewMajor}, #{reviewMinor}, #{reviewResult}, #{reviewKoglType}, #{reviewAiType},
      #{reviewOpinion}, #{reviewNote}, #{priorEvidence},
      #{judgedKoglType}, #{judgedAiType}, #{finalOpinion}, #{judgmentBasis}, #{processStatus}
    )
    on conflict (org_id, seq) do update set
      site_name       = excluded.site_name,
      category        = excluded.category,
      board_name      = excluded.board_name,
      post_title      = excluded.post_title,
      url             = excluded.url,
      description     = excluded.description,
      has_attachment  = excluded.has_attachment,
      prior_kogl_type = excluded.prior_kogl_type,
      produced_date   = excluded.produced_date,
      published_date  = excluded.published_date,
      review_major    = excluded.review_major,
      review_minor    = excluded.review_minor,
      review_result   = excluded.review_result,
      review_kogl_type = excluded.review_kogl_type,
      review_ai_type  = excluded.review_ai_type,
      review_opinion  = excluded.review_opinion,
      review_note     = excluded.review_note,
      prior_evidence  = excluded.prior_evidence,
      contract_docs   = case when process_item.web_edited_at is null then excluded.contract_docs else process_item.contract_docs end,
      judged_kogl_type = case when process_item.web_edited_at is null then excluded.judged_kogl_type else process_item.judged_kogl_type end,
      judged_ai_type  = case when process_item.web_edited_at is null then excluded.judged_ai_type else process_item.judged_ai_type end,
      final_opinion   = case when process_item.web_edited_at is null then excluded.final_opinion else process_item.final_opinion end,
      judgment_basis  = case when process_item.web_edited_at is null then excluded.judgment_basis else process_item.judgment_basis end,
      process_status  = case when process_item.web_edited_at is null then excluded.process_status else process_item.process_status end,
      updated_at      = now()
  </insert>

  <!--
    processed_at은 "처리완료"에 처음 도달한 시각만 남긴다: 이미 값이 있으면(먼저 처리완료로
    저장된 적이 있으면) 이번 저장이 다시 처리완료든 미처리로 되돌리든 손대지 않는다.
  -->
  <update id="updateProcessing">
    update process_item set
      contract_docs    = #{contractDocs},
      judged_kogl_type = #{judgedKoglType},
      judged_ai_type   = #{judgedAiType},
      final_opinion    = #{finalOpinion},
      judgment_basis   = #{judgmentBasis},
      process_status   = #{processStatus},
      web_edited_at    = now(),
      processed_at     = case
                            when #{processStatus} = #{doneStatus} and process_item.processed_at is null then now()
                            else process_item.processed_at
                          end,
      updated_at       = now()
    where org_id = #{orgId} and id = #{id}
  </update>

  <delete id="deleteById">
    delete from process_item where org_id = #{orgId} and id = #{id}
  </delete>

  <delete id="deleteByOrg">
    delete from process_item where org_id = #{orgId}
  </delete>

  <resultMap id="statsResultMap" type="kr.itn.itnhub.process.ProcessStats">
    <constructor>
      <arg column="total" javaType="_int"/>
      <arg column="done" javaType="_int"/>
    </constructor>
  </resultMap>

  <!-- 일괄 등록. 채운 항목만 반영되도록 coalesce를 쓰고, 처리완료로 바뀔 때만 처리시각을 찍는다. -->
  <update id="updateProcessingBulk">
    update process_item set
      process_status   = coalesce(#{processStatus}, process_status),
      judged_kogl_type = coalesce(#{judgedKoglType}, judged_kogl_type),
      final_opinion    = coalesce(#{finalOpinion}, final_opinion),
      review_note      = coalesce(#{reviewNote}, review_note),
      processed_at     = case when #{processStatus} = #{doneStatus} then now() else processed_at end,
      web_edited_at    = now(),
      updated_at       = now()
    where org_id = #{orgId}
      and id in
      <foreach item="id" collection="ids" open="(" separator="," close=")">#{id}</foreach>
  </update>

  <delete id="deleteByIds">
    delete from process_item
    where org_id = #{orgId}
      and id in
      <foreach item="id" collection="ids" open="(" separator="," close=")">#{id}</foreach>
  </delete>

  <select id="stats" resultMap="statsResultMap">
    select
      count(*) as total,
      count(*) filter (where process_status = #{doneStatus}) as done
    from process_item
    where org_id = #{orgId}
  </select>

</mapper>
