package com.ga.api.service.installment;

import com.ga.core.mapper.installment.InstallmentRatioMapper;
import com.ga.core.vo.installment.InstallmentPlanVO;
import com.ga.core.vo.installment.InstallmentRatioVO;
import com.ga.core.vo.installment.InstallmentStatus;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

@Component
@RequiredArgsConstructor
public class InstallmentPlanGenerator {

    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final DateTimeFormatter MONTH_FMT = DateTimeFormatter.ofPattern("yyyyMM");

    private final InstallmentRatioMapper ratioMapper;

    /**
     * 계약 체결일 기준 1~7차년 분급 계획 생성.
     * ratioPercent 합이 100%가 안 되는 경우 각 연차별 비율만큼 지급.
     */
    public List<InstallmentPlanVO> generate(Long contractId, BigDecimal totalCommission,
                                            LocalDate contractDate, String productCategory) {
        String baseDate = contractDate.format(DATE_FMT);
        List<InstallmentRatioVO> ratios = ratioMapper.selectAllActiveRatios(productCategory, baseDate);

        // 비율 합이 정확히 100%인 정규 스케줄이면 마지막 회차가 반올림 잔차를 흡수
        // → 분급 합계 == 원 수수료 보장 (부분지급 스케줄은 회차별 반올림 유지).
        boolean fullSchedule = sumRatios(ratios).compareTo(BigDecimal.valueOf(100)) == 0;
        BigDecimal allocated = BigDecimal.ZERO;

        List<InstallmentPlanVO> plans = new ArrayList<>();
        for (int i = 0; i < ratios.size(); i++) {
            InstallmentRatioVO ratio = ratios.get(i);
            // 마스터의 plan_month 가 NULL 이면 연 단위(첫 달 지급), NOT NULL 이면 그 회차(월) 그대로 사용.
            int planMonth = ratio.getPlanMonth() != null ? ratio.getPlanMonth() : 1;

            BigDecimal amount;
            if (fullSchedule && i == ratios.size() - 1) {
                amount = totalCommission.subtract(allocated);
            } else {
                amount = totalCommission.multiply(ratio.getRatioPercent())
                                        .divide(BigDecimal.valueOf(100), 0, RoundingMode.HALF_UP);
            }
            allocated = allocated.add(amount);

            InstallmentPlanVO plan = new InstallmentPlanVO();
            plan.setContractId(contractId);
            plan.setPlanYear(ratio.getPlanYear());
            plan.setPlanMonth(planMonth);
            plan.setSettleMonth(
                    contractDate.plusYears(ratio.getPlanYear()).plusMonths(planMonth - 1L).format(MONTH_FMT)
            );
            plan.setExpectedAmount(amount);
            plan.setStatus(InstallmentStatus.SCHEDULED.code());
            plans.add(plan);
        }
        return plans;
    }

    private BigDecimal sumRatios(List<InstallmentRatioVO> ratios) {
        return ratios.stream()
                .map(InstallmentRatioVO::getRatioPercent)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}
