package com.ga.batch.settlement.domain;

import com.ga.common.system.SystemConfigService;
import com.ga.core.vo.org.TaxType;
import com.ga.core.vo.org.VatType;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.math.BigDecimal;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;

/**
 * US-B 환수 원천세 역분개 검증.
 *
 * 환수(클로백) 우위로 gross<0 인 월에는 기납부 원천세를 역분개(음수)하여
 * 분기 원천세신고 누적이 정확히 net-off 되어야 한다. AggregateStep 은 reversalBase=|gross| 에
 * BatchTaxCalculator.calculate 를 적용하고 그 결과를 negate 하여 적재한다 — 본 테스트는 그 계산을 검증한다.
 */
@ExtendWith(MockitoExtension.class)
class WithholdingReversalTest {

    @Mock SystemConfigService configService;
    BatchTaxCalculator taxCalculator;

    @BeforeEach
    void setUp() {
        taxCalculator = new BatchTaxCalculator(configService);
        // 세율: configService 는 기본값(2번째 인자)을 그대로 반환 (사업 3.3% / 지방 10%)
        lenient().when(configService.getDecimal(anyString(), any(BigDecimal.class)))
                .thenAnswer(inv -> inv.getArgument(1));
    }

    @Test
    @DisplayName("역분개액 = |gross| 기준 원천세를 음수로 — 1,000,000 → 소득세 -33,000 / 지방세 -3,300")
    void reversal_amounts() {
        BigDecimal reversalBase = new BigDecimal("1000000"); // |gross| (환수 우위분)
        TaxBreakdown rev = taxCalculator.calculate(reversalBase, TaxType.BUSINESS_INCOME, VatType.NONE);

        BigDecimal incomeAdj = rev.incomeTax().negate();
        BigDecimal localAdj  = rev.localTax().negate();

        assertThat(incomeAdj).isEqualByComparingTo("-33000");  // 1,000,000 × 3.3%
        assertThat(localAdj).isEqualByComparingTo("-3300");    // 33,000 × 10%
    }

    @Test
    @DisplayName("양수월 원천징수 + 환수월 역분개 = 분기 누적 원천세 0 (net-off)")
    void quarter_nets_off() {
        // M월: gross +1,000,000 정상 지급 → 원천징수
        TaxBreakdown paid = taxCalculator.calculate(new BigDecimal("1000000"),
                TaxType.BUSINESS_INCOME, VatType.NONE);
        // M+2월: 환수만 발생 gross -1,000,000 → 역분개(음수)
        TaxBreakdown rev = taxCalculator.calculate(new BigDecimal("1000000"),
                TaxType.BUSINESS_INCOME, VatType.NONE);

        BigDecimal quarterWithheld = paid.incomeTax().add(rev.incomeTax().negate());
        BigDecimal quarterLocal    = paid.localTax().add(rev.localTax().negate());

        assertThat(quarterWithheld).isEqualByComparingTo("0");
        assertThat(quarterLocal).isEqualByComparingTo("0");
    }

    @Test
    @DisplayName("환수가 당월 양수분으로 완전 상계되면(gross>=0) 역분개 없음 — 당월 세금에 이미 반영")
    void no_reversal_when_gross_non_negative() {
        // gross = +500,000 (신규 1,500,000 − 환수 1,000,000) → 당월 과세 정상, 역분개 대상 아님
        TaxBreakdown within = taxCalculator.calculate(new BigDecimal("500000"),
                TaxType.BUSINESS_INCOME, VatType.NONE);
        assertThat(within.incomeTax()).isEqualByComparingTo("16500"); // 당월분만 과세
        // gross>=0 이므로 AggregateStep 의 역분개 블록(gross.signum()<0)은 진입하지 않는다.
    }
}
