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.SettleCorrectionMapper;
import com.ga.core.vo.settle.CorrectionStatus;
import com.ga.core.vo.settle.SettleCorrectionResp;
import com.ga.core.vo.settle.SettleCorrectionSaveReq;
import com.ga.core.vo.settle.SettleCorrectionSearchParam;
import com.ga.core.vo.settle.SettleCorrectionVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

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

    private final SettleCorrectionMapper correctionMapper;
    private final PeriodCloseService periodCloseService;

    public PageResponse<SettleCorrectionResp> list(SettleCorrectionSearchParam param) {
        param.startPage();
        return PageResponse.of(correctionMapper.selectList(param));
    }

    public SettleCorrectionResp detail(Long correctionId) {
        SettleCorrectionResp resp = correctionMapper.selectById(correctionId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    public List<SettleCorrectionResp> listByOriginalSettle(Long originalSettleId) {
        return correctionMapper.selectByOriginalSettleId(originalSettleId);
    }

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

        SettleCorrectionVO vo = new SettleCorrectionVO();
        vo.setOriginalSettleId(req.getOriginalSettleId());
        vo.setAgentId(req.getAgentId());
        vo.setSettleMonth(req.getSettleMonth());
        vo.setBeforeAmount(req.getBeforeAmount());
        vo.setAfterAmount(req.getAfterAmount());
        vo.setDiffAmount(req.getAfterAmount().subtract(req.getBeforeAmount()));
        vo.setReasonCode(req.getReasonCode());
        vo.setReasonDetail(req.getReasonDetail());
        vo.setStatus(CorrectionStatus.DRAFT.name());
        vo.setRequestedBy(SecurityUtil.getCurrentUserId());
        correctionMapper.insert(vo);
        return vo.getCorrectionId();
    }

    @Transactional
    public void approve(Long correctionId) {
        SettleCorrectionVO vo = correctionMapper.selectVoById(correctionId);
        if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
        if (!CorrectionStatus.DRAFT.name().equals(vo.getStatus())) {
            throw new BizException(ErrorCode.INVALID_STATUS, "DRAFT 상태만 승인 가능합니다");
        }
        correctionMapper.updateStatus(correctionId, CorrectionStatus.APPROVED.name(), SecurityUtil.getCurrentUserId());
    }

    @Transactional
    public void cancel(Long correctionId, String cancelReason) {
        SettleCorrectionVO vo = correctionMapper.selectVoById(correctionId);
        if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
        if (CorrectionStatus.APPLIED.name().equals(vo.getStatus())) {
            throw new BizException(ErrorCode.INVALID_STATUS, "이미 반영된 정정은 취소할 수 없습니다");
        }
        correctionMapper.cancel(correctionId, cancelReason, SecurityUtil.getCurrentUserId());
    }
}
