package com.zioinfo.kintex.settlement;

import java.util.List;

/**
 * F085 환불·취소 규정 산정(순수 함수 — 단위 테스트 대상).
 *
 * <p><b>환불율 = 취소 시점 D-일(행사 개막일까지 남은 일수) 구간별 요율</b>. 구간(brackets)은 룰셋
 * {@code rulesets/refund-v1.0.json}에서 로드하며(코드가 아닌 데이터로 버전 관리 — 규정 개정 대응),
 * 이 클래스는 구간 선택과 금액 산식만 담당한다.
 *
 * <ul>
 *   <li>base = 실 납입액(invoice.paid_amount) — 되돌려줄 수 있는 실제 금액</li>
 *   <li>refund = round(base × refundRatePercent / 100)</li>
 *   <li>forfeit = base − refund (공제·위약액)</li>
 * </ul>
 *
 * <p>D-일이 음수(행사 후)이면 환불 0. 개막일 미확정(daysBefore=null)은 호출부에서 별도 처리한다.
 */
public final class RefundCalc {

    private RefundCalc() {
    }

    /** 환불 구간 — minDaysBefore 이상 남았을 때 refundRatePercent 적용. */
    public record Bracket(int minDaysBefore, double refundRatePercent, String label) {
    }

    /**
     * D-일에 해당하는 구간을 선택한다. 구간이 minDaysBefore 내림차순이 아니어도 정확히 동작하도록
     * (조건을 만족하는 것 중 minDaysBefore가 가장 큰 구간)을 고른다. 매칭 없으면 null.
     * daysBefore가 음수(행사 후)이면 minDaysBefore=0 구간(또는 미매칭)로 귀결.
     */
    public static Bracket bracketFor(int daysBefore, List<Bracket> brackets) {
        if (brackets == null || brackets.isEmpty()) {
            return null;
        }
        Bracket best = null;
        for (Bracket b : brackets) {
            if (daysBefore >= b.minDaysBefore()) {
                if (best == null || b.minDaysBefore() > best.minDaysBefore()) {
                    best = b;
                }
            }
        }
        return best;
    }

    /** 환불액 = round(base × ratePercent / 100). base·rate 음수는 0으로 클램프. */
    public static long refundAmount(long base, double ratePercent) {
        if (base <= 0 || ratePercent <= 0) {
            return 0L;
        }
        double rate = Math.min(ratePercent, 100.0);
        return Math.round(base * rate / 100.0);
    }

    /** 공제(위약)액 = base − refund (음수 방지). */
    public static long forfeitAmount(long base, long refund) {
        return Math.max(0L, base - Math.max(0L, refund));
    }
}
