package com.zioinfo.kintex.ticket.cancel;

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 org.apache.ibatis.annotations.Update;

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

/**
 * F-B2 티켓 취소·환불 매퍼. tenant_id='KINTEX' 고정.
 * <p>★ camelCase 별칭 쌍따옴표({@code AS "x"}). ★ 날짜 비교는 파라미터 캐스팅.
 * <p>보안(§0-3): 조회에서 구매자 원문 컬럼은 SELECT 하지 않는다(마스킹/해시만).
 */
@Mapper
public interface TicketCancelMapper {

    /** 주문번호+연락처 해시 대조 → 취소 산정에 필요한 주문 원시값. 없으면 null. */
    @Select("""
            SELECT id            AS "id",
                   order_no      AS "orderNo",
                   event_id      AS "eventId",
                   product_id    AS "productId",
                   product_name  AS "productName",
                   qty,
                   unit_price    AS "unitPrice",
                   total_amount  AS "totalAmount",
                   status
            FROM ticket_order
            WHERE order_no = #{orderNo} AND buyer_contact_hash = #{contactHash}
            LIMIT 1
            """)
    Map<String, Object> findOrderForCancel(@Param("orderNo") String orderNo,
                                           @Param("contactHash") String contactHash);

    /** 행사 개막일(YYYY-MM-DD). 없으면 null. */
    @Select("SELECT to_char(start_date, 'YYYY-MM-DD') FROM event WHERE id = #{eventId}")
    String findEventStartDate(@Param("eventId") String eventId);

    /** 행사 특화 취소 구간(없으면 빈 목록 → 기본 구간 사용). */
    @Select("""
            SELECT min_days_before     AS "minDaysBefore",
                   refund_rate_percent AS "refundRatePercent",
                   label
            FROM ticket_cancel_bracket
            WHERE tenant_id = 'KINTEX' AND event_id = #{eventId}
            ORDER BY min_days_before DESC
            """)
    List<Map<String, Object>> findEventBrackets(@Param("eventId") String eventId);

    /** 기본 취소 구간(event_id IS NULL). */
    @Select("""
            SELECT min_days_before     AS "minDaysBefore",
                   refund_rate_percent AS "refundRatePercent",
                   label
            FROM ticket_cancel_bracket
            WHERE tenant_id = 'KINTEX' AND event_id IS NULL
            ORDER BY min_days_before DESC
            """)
    List<Map<String, Object>> findDefaultBrackets();

    /** 수수료 정책(행사 우선, 없으면 __default__). 없으면 null. */
    @Select("""
            SELECT booking_fee_per_ticket      AS "bookingFeePerTicket",
                   booking_fee_refund_min_days AS "bookingFeeRefundMinDays",
                   cancel_admin_fee_percent    AS "cancelAdminFeePercent",
                   version
            FROM ticket_fee_policy
            WHERE tenant_id = 'KINTEX' AND event_id = #{eventId}
            """)
    Map<String, Object> findFeePolicy(@Param("eventId") String eventId);

    /** 이미 취소된 주문 여부. */
    @Select("SELECT count(*) FROM ticket_cancellation WHERE tenant_id='KINTEX' AND order_id = #{orderId}")
    int countCancellation(@Param("orderId") String orderId);

    /** 주문 상태 → CANCELLED(조건부: PAID 만). 갱신행수 1이면 성공. */
    @Update("""
            UPDATE ticket_order
            SET status = 'CANCELLED', cancelled_at = now()
            WHERE tenant_id = 'KINTEX' AND id = #{orderId} AND status = 'PAID'
            """)
    int cancelOrder(@Param("orderId") String orderId);

    /** 재고 원복(취소). */
    @Update("""
            UPDATE ticket_product
            SET sold_qty = GREATEST(0, sold_qty - #{qty})
            WHERE tenant_id = 'KINTEX' AND id = #{productId}
            """)
    void restock(@Param("productId") String productId, @Param("qty") int qty);

    /** 취소 산정 스냅샷 저장(감사). */
    @Insert("""
            INSERT INTO ticket_cancellation
                (tenant_id, id, order_id, order_no, days_before, ticket_amount, booking_fee,
                 refund_rate, admin_fee, refund_amount, forfeit_amount, policy_version)
            VALUES
                ('KINTEX', #{id}, #{orderId}, #{orderNo}, #{daysBefore}, #{ticketAmount}, #{bookingFee},
                 #{refundRate}, #{adminFee}, #{refundAmount}, #{forfeitAmount}, #{policyVersion})
            """)
    void insertCancellation(Map<String, Object> row);
}
