package com.ga.batch.settlement.step;

import com.ga.batch.settlement.SettlementContext;
import com.ga.batch.settlement.calc.CommissionCalculator;
import com.ga.batch.settlement.domain.BatchInstallmentPlanGenerator;
import com.ga.batch.settlement.domain.BatchRegulatoryLimitChecker;
import com.ga.batch.settlement.domain.ViolationResult;
import com.ga.common.util.DateUtil;
import com.ga.common.util.MoneyUtil;
import com.ga.core.mapper.installment.InstallmentPlanMapper;
import com.ga.core.mapper.ledger.RecruitLedgerMapper;
import com.ga.core.mapper.product.ContractMapper;
import com.ga.core.vo.installment.InstallmentPlanVO;
import com.ga.core.vo.ledger.LedgerVO;
import com.ga.core.vo.product.ContractResp;
import com.ga.core.vo.product.ContractSearchParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * Step 4 — calcRecruit: 모집 수수료 계산 (계약 첫 회차)
 *
 * 원칙: 계약시점의 commission_rate / payout_rule 적용 (effective_from 기준)
 *
 * 추가: 1200%룰(BatchRegulatoryLimitChecker) 검증 후 한도 초과 계약은
 * InstallmentPlan(분급 7년) 생성. Step 4.5 역할을 Step 4 내에서 수행.
 */
@Slf4j
@Component
@JobScope
@RequiredArgsConstructor
public class CalcRecruitStep implements Tasklet {

    private final SettlementContext ctx;
    private final ContractMapper contractMapper;
    private final RecruitLedgerMapper recruitMapper;
    private final CommissionCalculator calculator;
    private final BatchRegulatoryLimitChecker regulatoryChecker;
    private final BatchInstallmentPlanGenerator installmentGenerator;
    private final InstallmentPlanMapper installmentPlanMapper;

    private static final int BATCH_SIZE = 1000;

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) {
        log.info("[Step4 calcRecruit] settleMonth={}", ctx.getSettleMonth());

        // 모집수수료 대상: 계약일이 정산월에 해당하는 계약
        String[] range = DateUtil.getMonthRange(ctx.getSettleMonth());
        ContractSearchParam param = new ContractSearchParam();
        param.setStartDate(range[0]);
        param.setEndDate(range[1]);
        param.setPageSize(Integer.MAX_VALUE);
        List<ContractResp> contracts = contractMapper.selectList(param);

        // 정산월 모집원장 초기화 (재계산 대비)
        recruitMapper.deleteBySettleMonth(ctx.getSettleMonth());

        List<LedgerVO> batch = new ArrayList<>(BATCH_SIZE);
        List<InstallmentPlanVO> installmentBatch = new ArrayList<>();
        int total = 0;
        int violationCount = 0;

        for (ContractResp c : contracts) {
            LedgerVO led = calculator.calcRecruitLedger(c, ctx.getSettleMonth());
            if (led == null || MoneyUtil.isZero(led.getAgentAmount())) continue;

            // 1200%룰 검증 (1차년도 한도)
            if (c.getContractDate() != null) {
                ViolationResult firstYearCheck = regulatoryChecker.checkFirstYear(
                        c.getContractId(), led.getAgentAmount(), c.getContractDate());

                if (firstYearCheck.violated()) {
                    log.warn("[Step4] 1200%룰 위반: contractId={}, msg={}",
                            c.getContractId(), firstYearCheck.message());
                    violationCount++;

                    // 1200%룰 위반 계약: 분급 계획 생성 (7년 35/25/15/10/7/5/3)
                    List<InstallmentPlanVO> plans = installmentGenerator.generate(
                            c.getContractId(), led.getAgentAmount(),
                            c.getContractDate(), c.getInsuranceType());
                    installmentBatch.addAll(plans);
                    // 위반 계약도 원장에는 기록 (감사 목적)
                }
            }

            batch.add(led);
            if (batch.size() >= BATCH_SIZE) {
                recruitMapper.batchInsert(batch);
                total += batch.size();
                batch.clear();
            }
        }
        if (!batch.isEmpty()) {
            recruitMapper.batchInsert(batch);
            total += batch.size();
        }

        // 분급 계획 일괄 저장
        if (!installmentBatch.isEmpty()) {
            installmentPlanMapper.insertBatch(installmentBatch);
            log.info("[Step4] installment plans created: {} (violations: {})",
                    installmentBatch.size(), violationCount);
        }

        ctx.setRecruitCount(total);
        log.info("[Step4] recruit ledger inserted: {}, regulatory violations: {}", total, violationCount);
        return RepeatStatus.FINISHED;
    }
}
