package com.ga.api.service.ledger;

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.ledger.ExceptionLedgerMapper;
import com.ga.core.mapper.ledger.MaintainLedgerMapper;
import com.ga.core.mapper.ledger.RecruitLedgerMapper;
import com.ga.core.mapstruct.ExceptionLedgerMapStruct;
import com.ga.core.vo.ledger.*;
import com.ga.core.vo.ledger.ApproveStatus;
import com.ga.core.vo.ledger.ExceptionLedgerStatus;
import org.apache.ibatis.cursor.Cursor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class LedgerService {

    private final RecruitLedgerMapper recruitMapper;
    private final MaintainLedgerMapper maintainMapper;
    private final ExceptionLedgerMapper exceptionMapper;
    private final ExceptionLedgerMapStruct exceptionLedgerMapStruct;

    @Transactional(readOnly = true)
    public PageResponse<LedgerResp> listRecruit(LedgerSearchParam param) {
        param.startPage();
        return PageResponse.of(recruitMapper.selectList(param));
    }

    @Transactional(readOnly = true)
    public PageResponse<LedgerResp> listMaintain(LedgerSearchParam param) {
        param.startPage();
        return PageResponse.of(maintainMapper.selectList(param));
    }

    @Transactional(readOnly = true)
    public PageResponse<ExceptionLedgerResp> listException(LedgerSearchParam param) {
        param.startPage();
        return PageResponse.of(exceptionMapper.selectList(param));
    }

    @Transactional(readOnly = true)
    public LedgerResp detailRecruit(Long ledgerId) {
        LedgerResp r = recruitMapper.selectDetailById(ledgerId);
        if (r == null) throw new BizException(ErrorCode.NOT_FOUND);
        return r;
    }

    @Transactional(readOnly = true)
    public LedgerResp detailMaintain(Long ledgerId) {
        LedgerResp r = maintainMapper.selectDetailById(ledgerId);
        if (r == null) throw new BizException(ErrorCode.NOT_FOUND);
        return r;
    }

    @Transactional(readOnly = true)
    public ExceptionLedgerResp detailException(Long ledgerId) {
        ExceptionLedgerResp r = exceptionMapper.selectDetailById(ledgerId);
        if (r == null) throw new BizException(ErrorCode.NOT_FOUND);
        return r;
    }

    @Transactional
    public Long createException(ExceptionLedgerSaveReq req) {
        ExceptionLedgerVO vo = exceptionLedgerMapStruct.toVO(req);
        vo.setRecurringLeft(req.getRecurringMonths());
        vo.setApproveStatus(ApproveStatus.PENDING.name());
        vo.setStatus(ExceptionLedgerStatus.NEW.name());
        exceptionMapper.insert(vo);
        return vo.getLedgerId();
    }

    public Cursor<LedgerExcelVO> exportRecruitCursor(LedgerSearchParam param) {
        return recruitMapper.selectCursorForExcel(param);
    }

    public Cursor<LedgerExcelVO> exportMaintainCursor(LedgerSearchParam param) {
        return maintainMapper.selectCursorForExcel(param);
    }

    @Transactional
    public void approveException(Long ledgerId, String status) {
        if (!ApproveStatus.APPROVED.name().equals(status) && !ApproveStatus.REJECTED.name().equals(status)) {
            throw new BizException(ErrorCode.INVALID_PARAMETER, "status는 APPROVED/REJECTED만 가능합니다");
        }
        Long approverId = SecurityUtil.getCurrentUserId();
        if (approverId == null) throw new BizException(ErrorCode.UNAUTHORIZED);
        exceptionMapper.updateApprove(ledgerId, status, approverId);
    }
}
