package com.ga.api.service.commission;

import com.ga.core.mapper.commission.AwardLedgerMapper;
import com.ga.core.mapper.commission.AwardRuleMapper;
import com.ga.core.vo.commission.AwardLedgerSaveReq;
import com.ga.core.vo.commission.AwardLedgerVO;
import com.ga.core.vo.commission.AwardRuleVO;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import com.ga.common.exception.BizException;

import java.math.BigDecimal;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class AwardServiceTest {

    @Mock AwardRuleMapper ruleMapper;
    @Mock AwardLedgerMapper ledgerMapper;

    @InjectMocks AwardService service;

    @Test
    @DisplayName("createLedger RATE: award_amount = base × award_rate (1,000,000 × 0.05 = 50,000)")
    void createLedger_rate() {
        AwardRuleVO rule = new AwardRuleVO();
        rule.setCalcType("RATE");
        rule.setAwardRate(new BigDecimal("0.05"));
        when(ruleMapper.selectActiveRule(eq("PERFORMANCE"), any())).thenReturn(rule);

        AwardLedgerSaveReq req = new AwardLedgerSaveReq();
        req.setAgentId(1L);
        req.setSettleMonth("202506");
        req.setAwardType("PERFORMANCE");
        req.setBaseAmount(new BigDecimal("1000000"));

        ArgumentCaptor<AwardLedgerVO> captor = ArgumentCaptor.forClass(AwardLedgerVO.class);
        when(ledgerMapper.insert(captor.capture())).thenReturn(1);

        service.createLedger(req);

        AwardLedgerVO saved = captor.getValue();
        assertThat(saved.getAwardAmount()).isEqualByComparingTo("50000.00");
        assertThat(saved.getStatus()).isEqualTo("CALCULATED");
    }

    @Test
    @DisplayName("createLedger FIXED: award_amount = award_fixed (200,000)")
    void createLedger_fixed() {
        AwardRuleVO rule = new AwardRuleVO();
        rule.setCalcType("FIXED");
        rule.setAwardFixed(new BigDecimal("200000"));
        when(ruleMapper.selectActiveRule(eq("NEW_RECRUIT"), any())).thenReturn(rule);

        AwardLedgerSaveReq req = new AwardLedgerSaveReq();
        req.setAgentId(2L);
        req.setSettleMonth("202506");
        req.setAwardType("NEW_RECRUIT");
        req.setBaseAmount(new BigDecimal("999999")); // FIXED이므로 base는 무시됨

        ArgumentCaptor<AwardLedgerVO> captor = ArgumentCaptor.forClass(AwardLedgerVO.class);
        when(ledgerMapper.insert(captor.capture())).thenReturn(1);

        service.createLedger(req);

        AwardLedgerVO saved = captor.getValue();
        assertThat(saved.getAwardAmount()).isEqualByComparingTo("200000.00");
    }

    @Test
    @DisplayName("createLedger: 실적이 threshold_amount 미달이면 시상 발동 안 함(예외) — 원장 미생성")
    void createLedger_belowThreshold_rejected() {
        AwardRuleVO rule = new AwardRuleVO();
        rule.setCalcType("RATE");
        rule.setAwardRate(new BigDecimal("0.05"));
        rule.setThresholdAmount(new BigDecimal("1000000")); // 기준 100만
        when(ruleMapper.selectActiveRule(eq("PERFORMANCE"), any())).thenReturn(rule);

        AwardLedgerSaveReq req = new AwardLedgerSaveReq();
        req.setAgentId(1L);
        req.setSettleMonth("202506");
        req.setAwardType("PERFORMANCE");
        req.setBaseAmount(new BigDecimal("800000")); // 기준 미달

        assertThatThrownBy(() -> service.createLedger(req))
                .isInstanceOf(BizException.class);
        verify(ledgerMapper, never()).insert(any());
    }

    @Test
    @DisplayName("createLedger: 실적이 threshold 이상이면 정상 발동 (경계 = 이상)")
    void createLedger_atThreshold_ok() {
        AwardRuleVO rule = new AwardRuleVO();
        rule.setCalcType("RATE");
        rule.setAwardRate(new BigDecimal("0.05"));
        rule.setThresholdAmount(new BigDecimal("1000000"));
        when(ruleMapper.selectActiveRule(eq("PERFORMANCE"), any())).thenReturn(rule);

        AwardLedgerSaveReq req = new AwardLedgerSaveReq();
        req.setAgentId(1L);
        req.setSettleMonth("202506");
        req.setAwardType("PERFORMANCE");
        req.setBaseAmount(new BigDecimal("1000000")); // 기준 정확히 충족

        ArgumentCaptor<AwardLedgerVO> captor = ArgumentCaptor.forClass(AwardLedgerVO.class);
        when(ledgerMapper.insert(captor.capture())).thenReturn(1);

        service.createLedger(req);

        assertThat(captor.getValue().getAwardAmount()).isEqualByComparingTo("50000.00");
    }
}
