package com.ga.batch.settlement.step;

import com.ga.batch.settlement.SettlementContext;
import com.ga.core.mapper.ledger.MaintainLedgerMapper;
import com.ga.core.mapper.ledger.RecruitLedgerMapper;
import com.ga.core.mapper.org.AgentMapper;
import com.ga.core.mapper.org.OrganizationMapper;
import com.ga.core.mapper.rule.RuleMapper;
import com.ga.core.mapper.settle.OverrideSettleMapper;
import com.ga.core.vo.org.AgentResp;
import com.ga.core.vo.org.AgentSearchParam;
import com.ga.core.vo.rule.OverrideRuleVO;
import com.ga.core.vo.settle.OverrideSettleVO;
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.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

import java.math.BigDecimal;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
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;

/**
 * 오버라이드 보험종류 조건(insurance_type_cond) 적용 검증.
 * 룰에 insurance_type_cond='LIFE' 가 있으면 base 가 LIFE 실적만으로 집계되어야 한다
 * (전 보험종류 합계에 율을 곱해 과지급되던 결함 수정).
 */
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class CalcOverrideStepTest {

    @Mock SettlementContext ctx;
    @Mock RuleMapper ruleMapper;
    @Mock AgentMapper agentMapper;
    @Mock OrganizationMapper organizationMapper;
    @Mock OverrideSettleMapper overrideMapper;
    @Mock RecruitLedgerMapper recruitMapper;
    @Mock MaintainLedgerMapper maintainMapper;

    CalcOverrideStep step;

    static final String MONTH = "202506";
    static final Long LOWER = 10L, UPPER = 99L, ORG = 100L;

    @BeforeEach
    void setUp() {
        step = new CalcOverrideStep(ctx, ruleMapper, agentMapper,
                organizationMapper, overrideMapper, recruitMapper, maintainMapper);
        when(ctx.getSettleMonth()).thenReturn(MONTH);

        // 하위 설계사(등급5) 1명 / 상위(등급1) 1명
        AgentResp lower = new AgentResp();
        lower.setAgentId(LOWER); lower.setOrgId(ORG); lower.setGradeId(5L);
        AgentResp upper = new AgentResp();
        upper.setAgentId(UPPER); upper.setOrgId(ORG); upper.setGradeId(1L);
        when(agentMapper.selectList(any(AgentSearchParam.class))).thenAnswer(inv -> {
            AgentSearchParam p = inv.getArgument(0);
            return p.getOrgId() != null ? List.of(upper) : List.of(lower); // 상위탐색 vs 전체ACTIVE
        });
        when(organizationMapper.selectAncestorIds(ORG)).thenReturn(List.of(ORG));
    }

    @Test
    @DisplayName("insurance_type_cond='LIFE' 룰: base 는 LIFE 실적만 집계, 전체합 미사용")
    void overrideBase_filteredByInsuranceType() {
        OverrideRuleVO rule = new OverrideRuleVO();
        rule.setFromGrade(5L);
        rule.setToGrade(1L);
        rule.setOverridePct(new BigDecimal("4"));        // 4%
        rule.setInsuranceTypeCond("LIFE");
        when(ruleMapper.selectOverrideRules()).thenReturn(new java.util.ArrayList<>(List.of(rule)));

        // LIFE 실적만 1,000,000 (전체합은 호출되면 안 됨)
        when(recruitMapper.sumByAgentMonthAndType(LOWER, MONTH, "LIFE")).thenReturn(new BigDecimal("1000000"));
        when(maintainMapper.sumByAgentMonthAndType(LOWER, MONTH, "LIFE")).thenReturn(BigDecimal.ZERO);

        ArgumentCaptor<List<OverrideSettleVO>> captor = ArgumentCaptor.forClass(List.class);
        when(overrideMapper.insertBatch(captor.capture())).thenReturn(1);

        step.execute(null, null);

        List<OverrideSettleVO> saved = captor.getValue();
        assertThat(saved).hasSize(1);
        assertThat(saved.get(0).getBaseAmount()).isEqualByComparingTo("1000000"); // LIFE만
        assertThat(saved.get(0).getOverrideAmount()).isEqualByComparingTo("40000.00"); // ×4%
        // 보험종류 한정 룰이면 전체합 집계는 호출되지 않아야 함
        verify(recruitMapper, never()).sumByAgentMonth(eq(LOWER), eq(MONTH));
        verify(maintainMapper, never()).sumByAgentMonth(eq(LOWER), eq(MONTH));
    }
}
