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.AgentGradeEvaluationMapper;
import com.ga.core.mapper.commission.GradeEvalRuleMapper;
import com.ga.core.vo.commission.AgentGradeEvaluationResp;
import com.ga.core.vo.commission.AgentGradeEvaluationSaveReq;
import com.ga.core.vo.commission.AgentGradeEvaluationSearchParam;
import com.ga.core.vo.commission.AgentGradeEvaluationVO;
import com.ga.core.vo.commission.GradeEvalRuleResp;
import com.ga.core.vo.commission.GradeEvalRuleSaveReq;
import com.ga.core.vo.commission.GradeEvalRuleSearchParam;
import com.ga.core.vo.commission.GradeEvalRuleVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;

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

    private final GradeEvalRuleMapper ruleMapper;
    private final AgentGradeEvaluationMapper evalMapper;

    // ── Rule ──────────────────────────────────────────────────────────────────

    public PageResponse<GradeEvalRuleResp> listRules(GradeEvalRuleSearchParam param) {
        param.startPage();
        return PageResponse.of(ruleMapper.selectList(param));
    }

    public GradeEvalRuleResp detailRule(Long ruleId) {
        GradeEvalRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    @Transactional
    public Long createRule(GradeEvalRuleSaveReq req) {
        GradeEvalRuleVO vo = new GradeEvalRuleVO();
        vo.setGradeId(req.getGradeId());
        vo.setMinScore(req.getMinScore());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.insert(vo);
        return vo.getRuleId();
    }

    @Transactional
    public void updateRule(Long ruleId, GradeEvalRuleSaveReq req) {
        GradeEvalRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        GradeEvalRuleVO vo = new GradeEvalRuleVO();
        vo.setRuleId(ruleId);
        vo.setGradeId(req.getGradeId());
        vo.setMinScore(req.getMinScore());
        vo.setEffectiveFrom(req.getEffectiveFrom());
        vo.setEffectiveTo(req.getEffectiveTo());
        ruleMapper.update(vo);
    }

    @Transactional
    public void deleteRule(Long ruleId) {
        GradeEvalRuleResp resp = ruleMapper.selectById(ruleId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        ruleMapper.delete(ruleId);
    }

    // ── Evaluation ────────────────────────────────────────────────────────────

    public PageResponse<AgentGradeEvaluationResp> listEvals(AgentGradeEvaluationSearchParam param) {
        param.startPage();
        return PageResponse.of(evalMapper.selectList(param));
    }

    public AgentGradeEvaluationResp detailEval(Long evalId) {
        AgentGradeEvaluationResp resp = evalMapper.selectById(evalId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    /**
     * 등급평가 생성.
     * selectActiveRuleByScore(score, 기준일)로 evaluated_grade_id 결정.
     * 매칭 룰 없으면 prevGradeId 유지 또는 null.
     */
    @Transactional
    public Long createEval(AgentGradeEvaluationSaveReq req) {
        LocalDate baseDate = LocalDate.now();
        GradeEvalRuleVO matchedRule = ruleMapper.selectActiveRuleByScore(req.getPerformanceScore(), baseDate);

        Long evaluatedGradeId = (matchedRule != null) ? matchedRule.getGradeId() : req.getPrevGradeId();

        AgentGradeEvaluationVO vo = new AgentGradeEvaluationVO();
        vo.setAgentId(req.getAgentId());
        vo.setEvalPeriod(req.getEvalPeriod());
        vo.setPerformanceScore(req.getPerformanceScore());
        vo.setPrevGradeId(req.getPrevGradeId());
        vo.setEvaluatedGradeId(evaluatedGradeId);
        vo.setStatus("EVALUATED");
        evalMapper.insert(vo);
        return vo.getEvalId();
    }

    /**
     * 등급평가 반영 액션 (EVALUATED → APPLIED).
     */
    @Transactional
    public void applyEval(Long evalId) {
        AgentGradeEvaluationResp resp = evalMapper.selectById(evalId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        if ("APPLIED".equals(resp.getStatus())) {
            throw new BizException(ErrorCode.INVALID_STATUS, "이미 반영된 평가입니다.");
        }
        evalMapper.updateStatus(evalId, "APPLIED");
    }

    @Transactional
    public void deleteEval(Long evalId) {
        AgentGradeEvaluationResp resp = evalMapper.selectById(evalId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        evalMapper.delete(evalId);
    }
}
