package com.ga.api.service.deduction;

import com.ga.common.exception.BizException;
import com.ga.common.exception.ErrorCode;
import com.ga.common.model.PageResponse;
import com.ga.core.mapper.settle.AgentDeductionMapper;
import com.ga.core.vo.settle.AgentDeductionResp;
import com.ga.core.vo.settle.AgentDeductionSaveReq;
import com.ga.core.vo.settle.AgentDeductionSearchParam;
import com.ga.core.vo.settle.AgentDeductionVO;
import com.ga.core.vo.settle.DeductionStatus;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class DeductionService {

    private final AgentDeductionMapper mapper;

    @Transactional(readOnly = true)
    public PageResponse<AgentDeductionResp> list(AgentDeductionSearchParam param) {
        param.startPage();
        return PageResponse.of(mapper.selectList(param));
    }

    @Transactional(readOnly = true)
    public AgentDeductionResp detail(Long deductionId) {
        AgentDeductionResp resp = mapper.selectDetailById(deductionId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    @Transactional
    public Long create(AgentDeductionSaveReq req) {
        if (mapper.countByAgentMonthType(req.getAgentId(), req.getSettleMonth(), req.getDeductionType()) > 0) {
            throw new BizException(ErrorCode.DUPLICATE_DATA,
                    "동일 설계사/정산월/차감유형 조합이 이미 존재합니다");
        }
        AgentDeductionVO vo = new AgentDeductionVO();
        vo.setAgentId(req.getAgentId());
        vo.setSettleMonth(req.getSettleMonth());
        vo.setDeductionType(req.getDeductionType());
        vo.setAmount(req.getAmount());
        vo.setDescription(req.getDescription());
        vo.setStatus(DeductionStatus.PENDING.name());
        mapper.insert(vo);
        return vo.getDeductionId();
    }

    @Transactional
    public void update(Long deductionId, AgentDeductionSaveReq req) {
        AgentDeductionVO vo = mapper.selectById(deductionId);
        if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
        if (!DeductionStatus.PENDING.name().equals(vo.getStatus())) {
            throw new BizException(ErrorCode.INVALID_PARAMETER, "PENDING 상태만 수정 가능합니다");
        }
        vo.setAmount(req.getAmount());
        vo.setDescription(req.getDescription());
        mapper.update(vo);
    }

    @Transactional
    public void cancel(Long deductionId) {
        AgentDeductionVO vo = mapper.selectById(deductionId);
        if (vo == null) throw new BizException(ErrorCode.NOT_FOUND);
        if (DeductionStatus.APPLIED.name().equals(vo.getStatus())) {
            throw new BizException(ErrorCode.INVALID_PARAMETER, "이미 적용된 차감은 취소할 수 없습니다");
        }
        mapper.updateStatus(deductionId, DeductionStatus.CANCELLED.name());
    }

    @Transactional(readOnly = true)
    public BigDecimal sumPendingByAgent(Long agentId, String settleMonth) {
        BigDecimal sum = mapper.sumPendingByAgent(agentId, settleMonth);
        return sum != null ? sum : BigDecimal.ZERO;
    }

    @Transactional(readOnly = true)
    public List<AgentDeductionVO> selectPendingByMonth(String settleMonth) {
        return mapper.selectPendingByMonth(settleMonth);
    }

    @Transactional(readOnly = true)
    public List<AgentDeductionVO> selectPendingByAgent(Long agentId, String settleMonth) {
        return mapper.selectPendingByAgent(agentId, settleMonth);
    }

    @Transactional
    public void markAsApplied(List<Long> deductionIds) {
        if (deductionIds.isEmpty()) return;
        mapper.updateStatusBatch(deductionIds, DeductionStatus.APPLIED.name());
    }
}
