package com.zioinfo.kintex.auction;

import com.zioinfo.kintex.auction.dto.AuctionDtos.QuoteLine;
import com.zioinfo.kintex.common.error.ApiException;
import com.zioinfo.kintex.common.error.ErrorCode;

import java.util.List;

/**
 * 견적서 금액 서버 재계산(순수 함수 — 단위 테스트 대상).
 *
 * <p>클라이언트가 보낸 금액을 신뢰하지 않고 서버가 라인아이템(수량×단가)으로 소계를 재계산한다.
 * <ul>
 *   <li><b>subtotal(소계)</b> = Σ(수량 × 단가) — 부가세 제외. 옥션 <b>경쟁/순위 금액</b>이며 {@code bid.total}에 저장된다
 *       (기존 시드·순위 로직과 정합: 순위·최저가는 부가세 제외 소계 기준).</li>
 *   <li><b>vat(부가세)</b> = round(subtotal × 10%).</li>
 *   <li><b>grandTotal(총액)</b> = subtotal + vat — 화면 표기용 부가세 포함 총액.</li>
 * </ul>
 * 음수 수량·단가, 소계 0 이하는 검증 오류(400).
 */
public final class QuotationCalc {

    public static final double VAT_RATE = 0.1;

    private QuotationCalc() {
    }

    /** subtotal=경쟁 금액(부가세 별도), vat=10%, grandTotal=subtotal+vat. */
    public record Totals(long subtotal, long vat, long grandTotal) {
    }

    /** 라인아이템 합산 재계산. */
    public static Totals fromLines(List<QuoteLine> lines) {
        if (lines == null || lines.isEmpty()) {
            throw new ApiException(ErrorCode.VALIDATION);
        }
        long subtotal = 0;
        for (QuoteLine l : lines) {
            long qty = l.qty() == null ? 0 : l.qty();
            long unit = l.unitPrice() == null ? 0 : l.unitPrice();
            if (qty < 0 || unit < 0) {
                throw new ApiException(ErrorCode.VALIDATION);
            }
            subtotal += qty * unit;
        }
        return finish(subtotal);
    }

    /** 라인아이템 미전송 시 폴백 — total 은 경쟁 금액(부가세 별도)으로 간주. */
    public static Totals fromTotal(Long total) {
        if (total == null) {
            throw new ApiException(ErrorCode.VALIDATION);
        }
        return finish(total);
    }

    private static Totals finish(long subtotal) {
        if (subtotal <= 0) {
            throw new ApiException(ErrorCode.VALIDATION);
        }
        long vat = Math.round(subtotal * VAT_RATE);
        return new Totals(subtotal, vat, subtotal + vat);
    }
}
