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.ReferralCommissionLedgerMapper;
import com.ga.core.mapper.commission.ReferralCommissionRuleMapper;
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 ReferralCommissionService {

    private final ReferralCommissionRuleMapper ruleMapper;
    private final ReferralCommissionLedgerMapper ledgerMapper;

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

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

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

    @Transactional
    public Long createRule(ReferralCommissionRuleSaveReq req) {
        ReferralCommissionRuleVO vo = new ReferralCommissionRuleVO();
        vo.setReferralType(req.getReferralType());
        vo.setCalcType(req.getCalcType());
        vo.setCommissionRate(req.getCommissionRate());
        vo.setFixedAmount(req.getFixedAmount());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.insert(vo);
        return vo.getRuleId();
    }

    @Transactional
    public void updateRule(Long ruleId, ReferralCommissionRuleSaveReq req) {
        ReferralCommissionRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        ReferralCommissionRuleVO vo = new ReferralCommissionRuleVO();
        vo.setRuleId(ruleId);
        vo.setReferralType(req.getReferralType());
        vo.setCalcType(req.getCalcType());
        vo.setCommissionRate(req.getCommissionRate());
        vo.setFixedAmount(req.getFixedAmount());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.update(vo);
    }

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

    // ── Ledger ────────────────────────────────────────────────────────────────

    public PageResponse<ReferralCommissionLedgerResp> listLedgers(ReferralCommissionLedgerSearchParam param) {
        param.startPage();
        return PageResponse.of(ledgerMapper.selectList(param));
    }

    public ReferralCommissionLedgerResp detailLedger(Long ledgerId) {
        ReferralCommissionLedgerResp resp = ledgerMapper.selectById(ledgerId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    @Transactional
    public Long createLedger(ReferralCommissionLedgerSaveReq req) {
        ReferralCommissionLedgerVO vo = new ReferralCommissionLedgerVO();
        vo.setContractId(req.getContractId());
        vo.setReferrerAgentId(req.getReferrerAgentId());
        vo.setSettleMonth(req.getSettleMonth());
        vo.setReferralType(req.getReferralType());
        vo.setBaseAmount(req.getBaseAmount());
        vo.setCommissionRate(req.getCommissionRate());

        // 소개·이관수수료 계산: 활성 룰의 calc_type 이 권위(RATE=base×rate / FIXED=fixed_amount).
        // 룰이 없을 때만 요청 commissionRate 로 폴백(수동 등록 호환).
        ReferralCommissionRuleVO rule = ruleMapper.selectActiveRule(
                req.getReferralType(), java.time.LocalDate.now());
        BigDecimal commissionAmount;
        if (rule != null) {
            if ("FIXED".equals(rule.getCalcType())) {
                if (rule.getFixedAmount() == null) throw new BizException(ErrorCode.NOT_FOUND);
                commissionAmount = rule.getFixedAmount().setScale(2, RoundingMode.HALF_UP);
                vo.setCommissionRate(null);
            } else { // RATE
                BigDecimal rate = req.getCommissionRate() != null
                        ? req.getCommissionRate() : rule.getCommissionRate();
                if (rate == null) throw new BizException(ErrorCode.NOT_FOUND);
                vo.setCommissionRate(rate);
                commissionAmount = req.getBaseAmount().multiply(rate).setScale(2, RoundingMode.HALF_UP);
            }
        } else if (req.getCommissionRate() != null) {
            // 활성 룰 없음 → 요청 rate 로 수동 계산
            commissionAmount = req.getBaseAmount()
                    .multiply(req.getCommissionRate())
                    .setScale(2, RoundingMode.HALF_UP);
        } else {
            throw new BizException(ErrorCode.NOT_FOUND);
        }
        vo.setCommissionAmount(commissionAmount);
        vo.setStatus("CALCULATED");
        ledgerMapper.insert(vo);
        return vo.getLedgerId();
    }
}
