package com.ga.common.util;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;

import static org.assertj.core.api.Assertions.assertThat;

class MoneyUtilTest {

    @Test
    @DisplayName("zero: null 은 0 으로 치환")
    void zero_null() {
        assertThat(MoneyUtil.zero(null)).isEqualTo(BigDecimal.ZERO);
        assertThat(MoneyUtil.zero(new BigDecimal("12.34"))).isEqualByComparingTo("12.34");
    }

    @Test
    @DisplayName("add/sub: null 안전, 정상 합/차")
    void add_sub() {
        assertThat(MoneyUtil.add(null, new BigDecimal("100"))).isEqualByComparingTo("100");
        assertThat(MoneyUtil.add(new BigDecimal("100"), null)).isEqualByComparingTo("100");
        assertThat(MoneyUtil.add(new BigDecimal("100"), new BigDecimal("50.50"))).isEqualByComparingTo("150.50");
        assertThat(MoneyUtil.sub(new BigDecimal("100"), new BigDecimal("30"))).isEqualByComparingTo("70");
        assertThat(MoneyUtil.sub(null, null)).isEqualByComparingTo("0");
    }

    @Test
    @DisplayName("mul: 소수점 2자리 HALF_UP")
    void mul_halfUp() {
        // 1.235 → 1.24 (HALF_UP)
        assertThat(MoneyUtil.mul(new BigDecimal("0.5"), new BigDecimal("2.47")))
                .isEqualByComparingTo("1.24");
        assertThat(MoneyUtil.mul(null, new BigDecimal("100"))).isEqualByComparingTo("0.00");
    }

    @Test
    @DisplayName("div: 0 으로 나누면 0 반환, null 안전")
    void div_byZero() {
        assertThat(MoneyUtil.div(new BigDecimal("100"), BigDecimal.ZERO)).isEqualByComparingTo("0");
        assertThat(MoneyUtil.div(new BigDecimal("100"), null)).isEqualByComparingTo("0");
        assertThat(MoneyUtil.div(new BigDecimal("100"), new BigDecimal("3")))
                .isEqualByComparingTo("33.33");
    }

    @Test
    @DisplayName("pct: amount × rate / 100, 2자리 HALF_UP")
    void pct_basic() {
        // 1,000,000 × 7.5% = 75,000.00
        assertThat(MoneyUtil.pct(new BigDecimal("1000000"), new BigDecimal("7.5")))
                .isEqualByComparingTo("75000.00");
        // 100 × 33.33% = 33.33
        assertThat(MoneyUtil.pct(new BigDecimal("100"), new BigDecimal("33.33")))
                .isEqualByComparingTo("33.33");
    }

    @Test
    @DisplayName("pct: null 입력은 0")
    void pct_null() {
        assertThat(MoneyUtil.pct(null, new BigDecimal("10"))).isEqualByComparingTo("0");
        assertThat(MoneyUtil.pct(new BigDecimal("100"), null)).isEqualByComparingTo("0");
    }

    @Test
    @DisplayName("tax: 기본 3.3% 원천징수")
    void tax_default() {
        // 1,000,000 × 3.3% = 33,000.00
        assertThat(MoneyUtil.tax(new BigDecimal("1000000")))
                .isEqualByComparingTo("33000.00");
    }

    @Test
    @DisplayName("tax: 사용자 지정 세율")
    void tax_customRate() {
        assertThat(MoneyUtil.tax(new BigDecimal("1000"), new BigDecimal("10")))
                .isEqualByComparingTo("100.00");
    }

    @Test
    @DisplayName("isZero/isPositive/isNegative")
    void signChecks() {
        assertThat(MoneyUtil.isZero(null)).isTrue();
        assertThat(MoneyUtil.isZero(BigDecimal.ZERO)).isTrue();
        assertThat(MoneyUtil.isZero(new BigDecimal("0.00"))).isTrue();
        assertThat(MoneyUtil.isPositive(new BigDecimal("0.01"))).isTrue();
        assertThat(MoneyUtil.isPositive(null)).isFalse();
        assertThat(MoneyUtil.isNegative(new BigDecimal("-1"))).isTrue();
        assertThat(MoneyUtil.isNegative(BigDecimal.ZERO)).isFalse();
    }

    @Test
    @DisplayName("fmt/fmtDec/fmtSign")
    void formatting() {
        assertThat(MoneyUtil.fmt(new BigDecimal("1234567"))).isEqualTo("1,234,567");
        assertThat(MoneyUtil.fmt(null)).isEmpty();
        assertThat(MoneyUtil.fmtDec(new BigDecimal("1234.5"))).isEqualTo("1,234.50");
        assertThat(MoneyUtil.fmtSign(new BigDecimal("100"))).isEqualTo("+100");
        assertThat(MoneyUtil.fmtSign(new BigDecimal("-100"))).isEqualTo("-100");
    }
}
