package com.zioinfo.kintex.hallassign;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

/**
 * M1 홀 배정·자동 견적 매퍼 — hall(마스터)·hall_assignment(배정)·event(개최기간).
 * camelCase 별칭은 쌍따옴표(PG 소문자 폴딩 함정). 기간 겹침은 [start<=to AND end>=from] 폐구간.
 * 선택 파라미터(null)는 {@code COALESCE(#{p}, 대체)}로 흡수해 PG 파라미터 타입 미결정 오류를 회피한다.
 */
@Mapper
public interface HallAssignMapper {

    /** 홀 마스터 전체(배정 보드 행·견적 근거). */
    @Select("""
            SELECT id,
                   exhibition_center AS "exhibitionCenter",
                   label,
                   area_m2 AS "areaM2",
                   floor_type AS "floorType",
                   booth_capacity AS "boothCapacity"
            FROM hall
            ORDER BY exhibition_center, id
            """)
    List<Map<String, Object>> findHalls();

    /** 단일 홀 마스터(견적 계산용). 없으면 null. */
    @Select("""
            SELECT id,
                   exhibition_center AS "exhibitionCenter",
                   label,
                   area_m2 AS "areaM2",
                   floor_type AS "floorType",
                   booth_capacity AS "boothCapacity"
            FROM hall
            WHERE id = #{hallId}
            """)
    Map<String, Object> findHallById(@Param("hallId") String hallId);

    /** 행사 개최기간(점유기간 미지정 시 보완). 없으면 null. */
    @Select("""
            SELECT id,
                   name,
                   to_char(start_date, 'YYYY-MM-DD') AS "startDate",
                   to_char(end_date, 'YYYY-MM-DD') AS "endDate"
            FROM event
            WHERE id = #{eventId}
            """)
    Map<String, Object> findEvent(@Param("eventId") String eventId);

    /**
     * 배정 보드 목록 — [from, to] 기간과 점유가 겹치는 배정(홀·기간 매트릭스).
     * eventId 지정 시 해당 행사만.
     */
    @Select("""
            SELECT ha.id,
                   ha.event_id AS "eventId",
                   e.name AS "eventName",
                   ha.hall_id AS "hallId",
                   h.label AS "hallLabel",
                   ha.is_primary AS "primary",
                   to_char(ha.occupy_start, 'YYYY-MM-DD') AS "occupyStart",
                   to_char(ha.occupy_end, 'YYYY-MM-DD') AS "occupyEnd",
                   ha.status,
                   ha.note
            FROM hall_assignment ha
            JOIN event e ON e.id = ha.event_id
            JOIN hall h ON h.id = ha.hall_id
            WHERE ha.occupy_start IS NOT NULL
              AND ha.occupy_start <= CAST(#{to} AS date)
              AND ha.occupy_end   >= CAST(#{from} AS date)
              AND ha.event_id = COALESCE(CAST(#{eventId} AS varchar), ha.event_id)
            ORDER BY ha.hall_id, ha.occupy_start
            """)
    List<Map<String, Object>> findAssignments(@Param("from") String from,
                                              @Param("to") String to,
                                              @Param("eventId") String eventId);

    /** 단일 배정 조회(생성 직후 응답·삭제 전 확인). 없으면 null. */
    @Select("""
            SELECT ha.id,
                   ha.event_id AS "eventId",
                   e.name AS "eventName",
                   ha.hall_id AS "hallId",
                   h.label AS "hallLabel",
                   ha.is_primary AS "primary",
                   to_char(ha.occupy_start, 'YYYY-MM-DD') AS "occupyStart",
                   to_char(ha.occupy_end, 'YYYY-MM-DD') AS "occupyEnd",
                   ha.status,
                   ha.note
            FROM hall_assignment ha
            JOIN event e ON e.id = ha.event_id
            JOIN hall h ON h.id = ha.hall_id
            WHERE ha.id = #{id}
            """)
    Map<String, Object> findAssignmentById(@Param("id") String id);

    /**
     * 홀·기간 겹침 충돌(같은 홀에서 [from, to] 폐구간과 겹치는 기존 배정).
     * excludeEventId/excludeAssignmentId(null 가능)로 자기 자신·재배정 대상 제외.
     */
    @Select("""
            SELECT ha.id AS "assignmentId",
                   ha.event_id AS "eventId",
                   e.name AS "eventName",
                   ha.hall_id AS "hallId",
                   h.label AS "hallLabel",
                   to_char(ha.occupy_start, 'YYYY-MM-DD') AS "occupyStart",
                   to_char(ha.occupy_end, 'YYYY-MM-DD') AS "occupyEnd"
            FROM hall_assignment ha
            JOIN event e ON e.id = ha.event_id
            JOIN hall h ON h.id = ha.hall_id
            WHERE ha.hall_id = #{hallId}
              AND ha.occupy_start IS NOT NULL
              AND ha.occupy_start <= CAST(#{to} AS date)
              AND ha.occupy_end   >= CAST(#{from} AS date)
              AND ha.event_id <> COALESCE(CAST(#{excludeEventId} AS varchar), '')
              AND ha.id <> COALESCE(CAST(#{excludeAssignmentId} AS varchar), '')
            ORDER BY ha.occupy_start
            """)
    List<Map<String, Object>> findConflicts(@Param("hallId") String hallId,
                                            @Param("from") String from,
                                            @Param("to") String to,
                                            @Param("excludeEventId") String excludeEventId,
                                            @Param("excludeAssignmentId") String excludeAssignmentId);

    /** 배정 생성. 점유기간·상태·비고 포함. */
    @Insert("""
            INSERT INTO hall_assignment
              (id, event_id, hall_id, is_primary, occupy_start, occupy_end, status, note, created_at, updated_at)
            VALUES
              (#{id}, #{eventId}, #{hallId}, #{primary},
               CAST(#{occupyStart} AS date), CAST(#{occupyEnd} AS date),
               'assigned', #{note}, now(), now())
            """)
    int insertAssignment(Map<String, Object> p);

    /** 배정 해제(삭제). 삭제 행 수 반환. */
    @Delete("DELETE FROM hall_assignment WHERE id = #{id}")
    int deleteAssignment(@Param("id") String id);
}
