package com.zioinfo.kintex.settlement;

import org.junit.jupiter.api.Test;

import java.util.List;

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

/**
 * F085 환불 산정 단위테스트 — D-일 구간 선택·환불액·공제액 산식 고정(refund-v1.0 기준 구간).
 */
class RefundCalcTest {

    private static final List<RefundCalc.Bracket> BRACKETS = List.of(
            new RefundCalc.Bracket(90, 100, "D-90 이전"),
            new RefundCalc.Bracket(60, 90, "D-60 ~ D-89"),
            new RefundCalc.Bracket(30, 70, "D-30 ~ D-59"),
            new RefundCalc.Bracket(14, 50, "D-14 ~ D-29"),
            new RefundCalc.Bracket(7, 30, "D-7 ~ D-13"),
            new RefundCalc.Bracket(0, 0, "D-6 이내"));

    @Test
    void selectsBracketByDaysBefore() {
        assertEquals(100, RefundCalc.bracketFor(120, BRACKETS).refundRatePercent());
        assertEquals(100, RefundCalc.bracketFor(90, BRACKETS).refundRatePercent());  // 경계 포함
        assertEquals(90, RefundCalc.bracketFor(89, BRACKETS).refundRatePercent());
        assertEquals(70, RefundCalc.bracketFor(30, BRACKETS).refundRatePercent());   // 데모: e-2026-smf D-30
        assertEquals(50, RefundCalc.bracketFor(20, BRACKETS).refundRatePercent());
        assertEquals(30, RefundCalc.bracketFor(7, BRACKETS).refundRatePercent());
        assertEquals(0, RefundCalc.bracketFor(3, BRACKETS).refundRatePercent());
        assertEquals(0, RefundCalc.bracketFor(0, BRACKETS).refundRatePercent());
    }

    @Test
    void afterEventHasNoMatchingPositiveBracketButLandsAtZero() {
        // 음수(행사 후)는 minDaysBefore=0 구간도 만족하지 못하므로 미매칭(호출부에서 afterEvent 0% 처리)
        assertNull(RefundCalc.bracketFor(-1, BRACKETS));
    }

    @Test
    void refundAmountRoundsHalfUp() {
        // base 3,960,000 × 70% = 2,772,000
        assertEquals(2_772_000L, RefundCalc.refundAmount(3_960_000L, 70));
        // 반올림(half-up): 3 × 50% = 1.5 → 2
        assertEquals(2L, RefundCalc.refundAmount(3L, 50));
        // 1,000,001 × 33.33% = 333,300.33 → 333,300
        assertEquals(333_300L, RefundCalc.refundAmount(1_000_001L, 33.33));
    }

    @Test
    void refundZeroWhenNoBaseOrZeroRate() {
        assertEquals(0L, RefundCalc.refundAmount(0L, 100));
        assertEquals(0L, RefundCalc.refundAmount(1_000_000L, 0));
    }

    @Test
    void rateClampedTo100() {
        assertEquals(1_000_000L, RefundCalc.refundAmount(1_000_000L, 150));
    }

    @Test
    void forfeitIsBaseMinusRefundNonNegative() {
        long base = 3_960_000L;
        long refund = RefundCalc.refundAmount(base, 70);
        assertEquals(base - refund, RefundCalc.forfeitAmount(base, refund));
        assertEquals(0L, RefundCalc.forfeitAmount(100L, 200L)); // 환불>기준(방어) → 0
    }

    @Test
    void emptyBracketsReturnNull() {
        assertNull(RefundCalc.bracketFor(50, List.of()));
    }
}
