package com.ga.api.service.settle;

import com.ga.common.exception.BizException;
import com.ga.common.exception.ErrorCode;
import com.ga.common.model.PageResponse;
import com.ga.common.util.SecurityUtil;
import com.ga.core.mapper.settle.IncentivePaymentMapper;
import com.ga.core.vo.settle.IncentivePayStatus;
import com.ga.core.vo.settle.IncentivePaymentResp;
import com.ga.core.vo.settle.IncentivePaymentSaveReq;
import com.ga.core.vo.settle.IncentivePaymentSearchParam;
import com.ga.core.vo.settle.IncentivePaymentVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

    private final IncentivePaymentMapper paymentMapper;
    private final PeriodCloseService periodCloseService;

    public PageResponse<IncentivePaymentResp> list(IncentivePaymentSearchParam param) {
        param.startPage();
        return PageResponse.of(paymentMapper.selectList(param));
    }

    public IncentivePaymentResp detail(Long incentivePayId) {
        IncentivePaymentResp resp = paymentMapper.selectById(incentivePayId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    @Transactional
    public Long create(IncentivePaymentSaveReq req) {
        // 마감 가드
        periodCloseService.assertNotClosed(req.getSettleMonth());

        IncentivePaymentVO vo = new IncentivePaymentVO();
        vo.setProgramId(req.getProgramId());
        vo.setAgentId(req.getAgentId());
        vo.setSettleMonth(req.getSettleMonth());
        vo.setBaseAmount(req.getBaseAmount());
        vo.setIncentiveAmount(req.getIncentiveAmount());
        vo.setStatus(IncentivePayStatus.CALCULATED.name());
        paymentMapper.insert(vo);
        return vo.getIncentivePayId();
    }

    @Transactional
    public void confirm(Long incentivePayId) {
        IncentivePaymentVO vo = paymentMapper.selectVoById(incentivePayId);
        if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
        if (!IncentivePayStatus.CALCULATED.name().equals(vo.getStatus())) {
            throw new BizException(ErrorCode.INVALID_STATUS, "CALCULATED 상태만 확정 가능합니다");
        }
        // 마감 가드
        periodCloseService.assertNotClosed(vo.getSettleMonth());
        paymentMapper.updateStatus(incentivePayId, IncentivePayStatus.CONFIRMED.name(), SecurityUtil.getCurrentUserId());
    }

    @Transactional
    public void cancel(Long incentivePayId, String cancelReason) {
        IncentivePaymentVO vo = paymentMapper.selectVoById(incentivePayId);
        if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
        if (IncentivePayStatus.PAID.name().equals(vo.getStatus())) {
            throw new BizException(ErrorCode.INVALID_STATUS, "지급완료된 시책은 취소할 수 없습니다");
        }
        paymentMapper.updateStatus(incentivePayId, IncentivePayStatus.CANCELLED.name(), SecurityUtil.getCurrentUserId());
    }
}
