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.BranchMgrAllowanceLedgerMapper;
import com.ga.core.mapper.commission.BranchMgrAllowanceRuleMapper;
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 BranchAllowanceService {

    private final BranchMgrAllowanceRuleMapper ruleMapper;
    private final BranchMgrAllowanceLedgerMapper ledgerMapper;

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

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

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

    @Transactional
    public Long createRule(BranchMgrAllowanceRuleSaveReq req) {
        BranchMgrAllowanceRuleVO vo = new BranchMgrAllowanceRuleVO();
        vo.setPositionCode(req.getPositionCode());
        vo.setAllowanceRate(req.getAllowanceRate());
        vo.setCapAmount(req.getCapAmount());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.insert(vo);
        return vo.getRuleId();
    }

    @Transactional
    public void updateRule(Long ruleId, BranchMgrAllowanceRuleSaveReq req) {
        BranchMgrAllowanceRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        BranchMgrAllowanceRuleVO vo = new BranchMgrAllowanceRuleVO();
        vo.setRuleId(ruleId);
        vo.setPositionCode(req.getPositionCode());
        vo.setAllowanceRate(req.getAllowanceRate());
        vo.setCapAmount(req.getCapAmount());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.update(vo);
    }

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

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

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

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

    @Transactional
    public Long createLedger(BranchMgrAllowanceLedgerSaveReq req) {
        // 수당액 = min(base × rate, cap) — cap NULL이면 상한 없음
        BigDecimal raw = req.getBaseAmount()
                .multiply(req.getAllowanceRate())
                .setScale(2, RoundingMode.HALF_UP);
        BigDecimal clawback = req.getClawbackAmount() != null ? req.getClawbackAmount() : BigDecimal.ZERO;

        // cap 적용: allowance = min(base×rate, cap). cap 미지정(NULL)이면 상한 없음.
        BigDecimal cap = req.getCapAmount();
        BigDecimal allowanceAmount = (cap != null && raw.compareTo(cap) > 0) ? cap : raw;

        BranchMgrAllowanceLedgerVO vo = new BranchMgrAllowanceLedgerVO();
        vo.setManagerAgentId(req.getManagerAgentId());
        vo.setOrgId(req.getOrgId());
        vo.setSettleMonth(req.getSettleMonth());
        vo.setBaseAmount(req.getBaseAmount());
        vo.setAllowanceRate(req.getAllowanceRate());
        vo.setAllowanceAmount(allowanceAmount);
        vo.setClawbackAmount(clawback);
        vo.setStatus("CALCULATED");
        ledgerMapper.insert(vo);
        return vo.getLedgerId();
    }
}
