package com.ga.api.service.org;

import com.ga.common.code.CommonCodeService;
import com.ga.common.exception.BizException;
import com.ga.common.exception.ErrorCode;
import com.ga.common.model.PageResponse;
import com.ga.core.mapper.org.AgentMapper;
import com.ga.core.vo.org.*;
import com.ga.core.vo.org.AgentStatus;
import com.ga.core.vo.org.TaxType;
import com.ga.core.vo.org.VatType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cursor.Cursor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class AgentService {

    private final AgentMapper mapper;
    private final CommonCodeService codeService;

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

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

    @Transactional
    public Long create(AgentSaveReq req) {
        if (req.getLicenseNo() != null && mapper.existsByLicenseNo(req.getLicenseNo()) > 0) {
            throw new BizException(ErrorCode.DUPLICATE_DATA, "이미 등록된 사번입니다");
        }
        AgentVO vo = toVO(req, null);
        vo.setStatus(AgentStatus.ACTIVE.name());
        mapper.insert(vo);
        // 입사 이력 기록
        AgentOrgHistoryVO h = new AgentOrgHistoryVO();
        h.setAgentId(vo.getAgentId());
        h.setToOrgId(vo.getOrgId());
        h.setToGradeId(vo.getGradeId());
        h.setChangeType("JOIN");
        h.setChangeDate(req.getJoinDate() != null ? req.getJoinDate() : java.time.LocalDate.now());
        mapper.insertHistory(h);
        return vo.getAgentId();
    }

    @Transactional
    public void update(Long agentId, AgentSaveReq req) {
        AgentVO old = mapper.selectById(agentId);
        if (old == null) throw new BizException(ErrorCode.NOT_FOUND);
        AgentVO vo = toVO(req, agentId);
        vo.setStatus(old.getStatus());
        mapper.update(vo);

        // 조직/직급 변경 시 이력
        if (!java.util.Objects.equals(old.getOrgId(), vo.getOrgId())
                || !java.util.Objects.equals(old.getGradeId(), vo.getGradeId())) {
            AgentOrgHistoryVO h = new AgentOrgHistoryVO();
            h.setAgentId(agentId);
            h.setFromOrgId(old.getOrgId());
            h.setToOrgId(vo.getOrgId());
            h.setFromGradeId(old.getGradeId());
            h.setToGradeId(vo.getGradeId());
            h.setChangeType(!java.util.Objects.equals(old.getGradeId(), vo.getGradeId()) ? "PROMOTE" : "TRANSFER");
            h.setChangeDate(java.time.LocalDate.now());
            mapper.insertHistory(h);
        }
    }

    @Transactional
    public void changeStatus(Long agentId, String status) {
        codeService.validateCode("AGENT_STATUS", status);
        mapper.updateStatus(agentId, status);
    }

    @Transactional(readOnly = true)
    public java.util.List<AgentOrgHistoryResp> history(Long agentId) {
        return mapper.selectHistoryResp(agentId);
    }

    public Cursor<AgentExcelVO> exportCursor(AgentSearchParam param) {
        return mapper.selectCursorForExcel(param);
    }

    private AgentVO toVO(AgentSaveReq req, Long agentId) {
        AgentVO vo = new AgentVO();
        vo.setAgentId(agentId);
        vo.setOrgId(req.getOrgId());
        vo.setGradeId(req.getGradeId());
        vo.setAgentName(req.getAgentName());
        vo.setResidentNo(req.getResidentNo());
        vo.setLicenseNo(req.getLicenseNo());
        vo.setPhone(req.getPhone());
        vo.setEmail(req.getEmail());
        vo.setBankCode(req.getBankCode());
        vo.setAccountNo(req.getAccountNo());
        vo.setJoinDate(req.getJoinDate());

        String taxType = req.getTaxType() != null ? req.getTaxType() : TaxType.BUSINESS_INCOME.name();
        String vatType = req.getVatType() != null ? req.getVatType() : VatType.NONE.name();
        vo.setTaxType(taxType);
        vo.setVatType(vatType);
        vo.setBusinessNo(req.getBusinessNo());

        if (TaxType.BUSINESS_INCOME.name().equals(taxType)
                && (req.getBusinessNo() == null || req.getBusinessNo().isBlank())) {
            log.warn("agentId={} taxType=BUSINESS_INCOME이지만 businessNo가 비어있습니다", agentId);
        }
        return vo;
    }
}
