package com.ga.api.service.commission;

import com.ga.common.exception.BizException;
import com.ga.common.exception.ErrorCode;
import com.ga.common.model.PageResponse;
import com.ga.core.mapper.commission.PersistencyBonusMapper;
import com.ga.core.mapper.commission.PersistencyBonusRuleMapper;
import com.ga.core.vo.commission.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class PersistencyBonusService {

    private final PersistencyBonusRuleMapper ruleMapper;
    private final PersistencyBonusMapper bonusMapper;

    // ── Rule ──────────────────────────────────────────────────────────────────

    public PageResponse<PersistencyBonusRuleResp> listRules(PersistencyBonusRuleSearchParam param) {
        param.startPage();
        return PageResponse.of(ruleMapper.selectList(param));
    }

    public PersistencyBonusRuleResp detailRule(Long ruleId) {
        PersistencyBonusRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    @Transactional
    public Long createRule(PersistencyBonusRuleSaveReq req) {
        PersistencyBonusRuleVO vo = new PersistencyBonusRuleVO();
        vo.setGradeId(req.getGradeId());
        vo.setRetentionMonth(req.getRetentionMonth());
        vo.setRetentionRateThreshold(req.getRetentionRateThreshold());
        vo.setBonusType(req.getBonusType());
        vo.setBonusValue(req.getBonusValue());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.insert(vo);
        return vo.getRuleId();
    }

    @Transactional
    public void updateRule(Long ruleId, PersistencyBonusRuleSaveReq req) {
        PersistencyBonusRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        PersistencyBonusRuleVO vo = new PersistencyBonusRuleVO();
        vo.setRuleId(ruleId);
        vo.setGradeId(req.getGradeId());
        vo.setRetentionMonth(req.getRetentionMonth());
        vo.setRetentionRateThreshold(req.getRetentionRateThreshold());
        vo.setBonusType(req.getBonusType());
        vo.setBonusValue(req.getBonusValue());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.update(vo);
    }

    @Transactional
    public void deleteRule(Long ruleId) {
        PersistencyBonusRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        ruleMapper.delete(ruleId);
    }

    // ── Bonus ─────────────────────────────────────────────────────────────────

    public PageResponse<PersistencyBonusResp> listBonuses(PersistencyBonusSearchParam param) {
        param.startPage();
        return PageResponse.of(bonusMapper.selectList(param));
    }

    public PersistencyBonusResp detailBonus(Long bonusId) {
        PersistencyBonusResp resp = bonusMapper.selectById(bonusId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    /**
     * 수동 지급 등록/갱신 — UNIQUE(agent_id, base_month, retention_month) 기반 upsert.
     */
    @Transactional
    public void upsertBonus(PersistencyBonusSaveReq req) {
        BigDecimal bonusAmount = req.getBonusAmount();

        // 지속수당 지급 게이트: 룰이 지정되면 유지율이 임계(retention_rate_threshold) 이상이어야 지급.
        // FIXED형 룰이면 지급액을 룰의 bonus_value(정액)로 도출한다.
        if (req.getRuleId() != null) {
            PersistencyBonusRuleResp rule = ruleMapper.selectById(req.getRuleId());
            if (rule == null) throw new BizException(ErrorCode.NOT_FOUND);
            if (rule.getRetentionRateThreshold() != null
                    && (req.getRetentionRate() == null
                        || req.getRetentionRate().compareTo(rule.getRetentionRateThreshold()) < 0)) {
                throw new BizException(ErrorCode.INVALID_PARAMETER,
                        "유지율이 지급 임계(" + rule.getRetentionRateThreshold() + ")에 미달합니다.");
            }
            if ("FIXED".equals(rule.getBonusType()) && rule.getBonusValue() != null) {
                bonusAmount = rule.getBonusValue().setScale(2, RoundingMode.HALF_UP);
            }
        }

        PersistencyBonusVO vo = new PersistencyBonusVO();
        vo.setAgentId(req.getAgentId());
        vo.setRuleId(req.getRuleId());
        vo.setBaseMonth(req.getBaseMonth());
        vo.setRetentionMonth(req.getRetentionMonth());
        vo.setSettleMonth(req.getSettleMonth());
        vo.setRetentionRate(req.getRetentionRate());
        vo.setBonusAmount(bonusAmount);
        vo.setStatus("CALCULATED");
        bonusMapper.upsert(vo);
    }
}
