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.SettlingSupportLedgerMapper;
import com.ga.core.mapper.commission.SettlingSupportRuleMapper;
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 SettlingSupportService {

    private final SettlingSupportRuleMapper ruleMapper;
    private final SettlingSupportLedgerMapper ledgerMapper;

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

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

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

    @Transactional
    public Long createRule(SettlingSupportRuleSaveReq req) {
        SettlingSupportRuleVO vo = new SettlingSupportRuleVO();
        vo.setAgentGrade(req.getAgentGrade());
        vo.setSupportAmount(req.getSupportAmount());
        vo.setDurationMonths(req.getDurationMonths());
        vo.setClawbackMonths(req.getClawbackMonths());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.insert(vo);
        return vo.getRuleId();
    }

    @Transactional
    public void updateRule(Long ruleId, SettlingSupportRuleSaveReq req) {
        SettlingSupportRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        SettlingSupportRuleVO vo = new SettlingSupportRuleVO();
        vo.setRuleId(ruleId);
        vo.setAgentGrade(req.getAgentGrade());
        vo.setSupportAmount(req.getSupportAmount());
        vo.setDurationMonths(req.getDurationMonths());
        vo.setClawbackMonths(req.getClawbackMonths());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.update(vo);
    }

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

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

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

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

    @Transactional
    public Long createLedger(SettlingSupportLedgerSaveReq req) {
        BigDecimal clawback = req.getClawbackAmount() != null ? req.getClawbackAmount() : BigDecimal.ZERO;
        // 환수액은 음수 불가, 지원금 초과 불가 (net 음수 방지)
        if (clawback.signum() < 0 || clawback.compareTo(req.getSupportAmount()) > 0) {
            throw new BizException(ErrorCode.BAD_REQUEST,
                    String.format("환수액(%s)은 0 이상이며 지원금(%s)을 초과할 수 없습니다",
                            clawback, req.getSupportAmount()));
        }
        // 실지급액 = support_amount - clawback_amount
        BigDecimal netAmount = req.getSupportAmount()
                .subtract(clawback)
                .setScale(2, RoundingMode.HALF_UP);

        SettlingSupportLedgerVO vo = new SettlingSupportLedgerVO();
        vo.setAgentId(req.getAgentId());
        vo.setSettleMonth(req.getSettleMonth());
        vo.setSupportAmount(req.getSupportAmount());
        vo.setClawbackAmount(clawback);
        vo.setNetAmount(netAmount);
        vo.setStatus("CALCULATED");
        ledgerMapper.insert(vo);
        return vo.getLedgerId();
    }
}
