package com.zioinfo.kintex.ticket.cancel;

import com.zioinfo.kintex.ticket.cancel.TicketCancelCalc.Bracket;
import com.zioinfo.kintex.ticket.cancel.TicketCancelCalc.Result;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
 * F-B2 티켓 취소·환불 산정 단위테스트 — 다구간 환불율 + 예매수수료 별도 + 취소 관리수수료 공제.
 */
class TicketCancelCalcTest {

    // 기본 구간(V95 시드와 동일): D-10 100% / D-7 90% / D-3 70% / D-1 50% / D-0 0%
    private static final List<Bracket> BRACKETS = List.of(
            new Bracket(10, 100.0, "D-10 전액"),
            new Bracket(7, 90.0, "D-7 90%"),
            new Bracket(3, 70.0, "D-3 70%"),
            new Bracket(1, 50.0, "D-1 50%"),
            new Bracket(0, 0.0, "당일 환불불가"));

    @Test
    void farBeforeEvent_fullRefund_plusBookingFeeRefunded() {
        // D-12, 티켓 30,000 · 예매수수료 2,000 · 예매수수료 환불 최소 7일 · 관리수수료 5%
        // 환불율 100% → ticketRefund 30,000, adminFee=round(30000*5%)=1,500,
        // bookingFeeRefund=2,000(D-12>=7), refund=30,000-1,500+2,000=30,500
        Result r = TicketCancelCalc.compute(12, 30_000, 2_000, BRACKETS, 7, 5.0);
        assertEquals(100.0, r.refundRatePercent());
        assertEquals(30_000, r.ticketRefund());
        assertEquals(1_500, r.adminFee());
        assertEquals(2_000, r.bookingFeeRefund());
        assertEquals(30_500, r.refundAmount());
        assertEquals(1_500, r.forfeitAmount());  // (30000+2000)-30500
    }

    @Test
    void nearEvent_partialRefund_bookingFeeForfeited() {
        // D-2, 티켓 30,000 · 예매수수료 2,000 · 최소 7일 · 관리수수료 5%
        // 구간 D-1(50%) → ticketRefund 15,000, adminFee=750, bookingFeeRefund=0(D-2<7)
        // refund=15,000-750+0=14,250, forfeit=(32,000-14,250)=17,750
        Result r = TicketCancelCalc.compute(2, 30_000, 2_000, BRACKETS, 7, 5.0);
        assertEquals(50.0, r.refundRatePercent());
        assertEquals(15_000, r.ticketRefund());
        assertEquals(750, r.adminFee());
        assertEquals(0, r.bookingFeeRefund());
        assertEquals(14_250, r.refundAmount());
        assertEquals(17_750, r.forfeitAmount());
    }

    @Test
    void eventDayOrAfter_noRefund() {
        Result r0 = TicketCancelCalc.compute(0, 30_000, 2_000, BRACKETS, 7, 5.0);
        assertEquals(0.0, r0.refundRatePercent());
        assertEquals(0, r0.refundAmount());
        assertEquals(32_000, r0.forfeitAmount());

        Result rNeg = TicketCancelCalc.compute(-3, 30_000, 2_000, BRACKETS, 7, 5.0);
        assertEquals(0, rNeg.refundAmount());
    }

    @Test
    void bracketFor_selectsHighestMatching() {
        assertEquals(7, TicketCancelCalc.bracketFor(8, BRACKETS).minDaysBefore());
        assertEquals(10, TicketCancelCalc.bracketFor(50, BRACKETS).minDaysBefore());
        assertEquals(0, TicketCancelCalc.bracketFor(0, BRACKETS).minDaysBefore());
    }
}
