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.AgentReserveFundMapper;
import com.ga.core.vo.commission.AgentReserveFundResp;
import com.ga.core.vo.commission.AgentReserveFundSaveReq;
import com.ga.core.vo.commission.AgentReserveFundSearchParam;
import com.ga.core.vo.commission.AgentReserveFundVO;
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 ReserveFundService {

    private final AgentReserveFundMapper reserveFundMapper;

    public PageResponse<AgentReserveFundResp> list(AgentReserveFundSearchParam param) {
        param.startPage();
        return PageResponse.of(reserveFundMapper.selectList(param));
    }

    public AgentReserveFundResp detail(Long reserveId) {
        AgentReserveFundResp resp = reserveFundMapper.selectById(reserveId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    /**
     * 적립금 생성(upsert).
     * balance = (직전월 balance or 0) + reserveIn − reserveOut. setScale(2, HALF_UP).
     * 해당 월 레코드가 이미 존재하면 update, 없으면 insert.
     */
    @Transactional
    public Long create(AgentReserveFundSaveReq req) {
        AgentReserveFundVO prevMonth = reserveFundMapper.selectLatestBefore(req.getAgentId(), req.getSettleMonth());
        BigDecimal prevBalance = (prevMonth != null && prevMonth.getBalance() != null)
                ? prevMonth.getBalance()
                : BigDecimal.ZERO;

        BigDecimal balance = prevBalance
                .add(req.getReserveIn())
                .subtract(req.getReserveOut())
                .setScale(2, RoundingMode.HALF_UP);

        AgentReserveFundVO existing = reserveFundMapper.selectByAgentAndMonth(req.getAgentId(), req.getSettleMonth());
        if (existing != null) {
            existing.setReserveIn(req.getReserveIn());
            existing.setReserveOut(req.getReserveOut());
            existing.setBalance(balance);
            reserveFundMapper.update(existing);
            return existing.getReserveId();
        }

        AgentReserveFundVO vo = new AgentReserveFundVO();
        vo.setAgentId(req.getAgentId());
        vo.setSettleMonth(req.getSettleMonth());
        vo.setReserveIn(req.getReserveIn());
        vo.setReserveOut(req.getReserveOut());
        vo.setBalance(balance);
        reserveFundMapper.insert(vo);
        return vo.getReserveId();
    }
}
