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 org.junit.jupiter.api.Test;

import java.util.List;

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

/**
 * M15 견적서 서버 재계산 단위테스트 — 소계=Σ(수량×단가)·부가세 10%·총액·검증.
 * 클라이언트가 보낸 금액을 신뢰하지 않고 서버가 라인아이템으로 재산출함을 고정한다.
 */
class QuotationCalcTest {

    @Test
    void fromLines_sumsQtyTimesUnit_andAppliesVat() {
        // 골조 48×45,000 + 전기 1×1,240,000 + 그래픽 12×95,000 = 2,160,000 + 1,240,000 + 1,140,000 = 4,540,000
        List<QuoteLine> lines = List.of(
                new QuoteLine("골조", "알루미늄 프로파일", 48L, 45_000L),
                new QuoteLine("전기", "분전반 일체", 1L, 1_240_000L),
                new QuoteLine("그래픽", "출력·시공", 12L, 95_000L));

        QuotationCalc.Totals t = QuotationCalc.fromLines(lines);

        assertEquals(4_540_000L, t.subtotal());          // 부가세 별도 경쟁 금액
        assertEquals(454_000L, t.vat());                 // 10%
        assertEquals(4_994_000L, t.grandTotal());        // 소계 + 부가세
    }

    @Test
    void fromLines_roundsVatHalfUp() {
        // 소계 8,399,999 → 부가세 round(839,999.9)=840,000
        QuotationCalc.Totals t = QuotationCalc.fromLines(
                List.of(new QuoteLine("일식", "복합공사", 1L, 8_399_999L)));
        assertEquals(8_399_999L, t.subtotal());
        assertEquals(840_000L, t.vat());
        assertEquals(9_239_999L, t.grandTotal());
    }

    @Test
    void fromTotal_treatsAmountAsExVatSubtotal() {
        QuotationCalc.Totals t = QuotationCalc.fromTotal(8_400_000L);
        assertEquals(8_400_000L, t.subtotal());
        assertEquals(840_000L, t.vat());
        assertEquals(9_240_000L, t.grandTotal());
    }

    @Test
    void rejectsNegativeQuantityOrUnitPrice() {
        ApiException e1 = assertThrows(ApiException.class,
                () -> QuotationCalc.fromLines(List.of(new QuoteLine("골조", "자재", -1L, 45_000L))));
        assertEquals(ErrorCode.VALIDATION, e1.getCode());

        assertThrows(ApiException.class,
                () -> QuotationCalc.fromLines(List.of(new QuoteLine("골조", "자재", 5L, -100L))));
    }

    @Test
    void rejectsEmptyLinesAndZeroSubtotal() {
        assertThrows(ApiException.class, () -> QuotationCalc.fromLines(List.of()));
        assertThrows(ApiException.class,
                () -> QuotationCalc.fromLines(List.of(new QuoteLine("무상", "샘플", 0L, 0L))));
        assertThrows(ApiException.class, () -> QuotationCalc.fromTotal(0L));
        assertThrows(ApiException.class, () -> QuotationCalc.fromTotal(null));
    }
}
