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.JointContractMapper;
import com.ga.core.vo.commission.JointContractResp;
import com.ga.core.vo.commission.JointContractSaveReq;
import com.ga.core.vo.commission.JointContractSearchParam;
import com.ga.core.vo.commission.JointContractVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

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

    private final JointContractMapper jointContractMapper;

    public PageResponse<JointContractResp> list(JointContractSearchParam param) {
        param.startPage();
        return PageResponse.of(jointContractMapper.selectList(param));
    }

    public JointContractResp detail(Long jointId) {
        JointContractResp resp = jointContractMapper.selectById(jointId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        return resp;
    }

    /**
     * 공동계약 생성.
     * 기존 share_rate 합 + 신규 share_rate > 1.0 이면 E411 예외.
     */
    @Transactional
    public Long create(JointContractSaveReq req) {
        validateShareRate(req.getContractId(), null, req.getShareRate());
        JointContractVO vo = new JointContractVO();
        vo.setContractId(req.getContractId());
        vo.setAgentId(req.getAgentId());
        vo.setRole(req.getRole());
        vo.setShareRate(req.getShareRate());
        jointContractMapper.insert(vo);
        return vo.getJointId();
    }

    /**
     * 공동계약 수정.
     * 기존 share_rate 합(자신 제외) + 수정 share_rate > 1.0 이면 E411 예외.
     */
    @Transactional
    public void update(Long jointId, JointContractSaveReq req) {
        JointContractResp resp = jointContractMapper.selectById(jointId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        // 계약 이동은 허용하지 않음 — 검증/갱신 모두 기존 레코드의 contractId 기준
        validateShareRate(resp.getContractId(), jointId, req.getShareRate());
        JointContractVO vo = new JointContractVO();
        vo.setJointId(jointId);
        vo.setContractId(resp.getContractId());
        vo.setAgentId(req.getAgentId());
        vo.setRole(req.getRole());
        vo.setShareRate(req.getShareRate());
        jointContractMapper.update(vo);
    }

    @Transactional
    public void delete(Long jointId) {
        JointContractResp resp = jointContractMapper.selectById(jointId);
        if (resp == null) throw new BizException(ErrorCode.NOT_FOUND);
        jointContractMapper.delete(jointId);
    }

    /**
     * 계약별 share_rate 합 검증.
     * excludeJointId: 수정 시 자신 레코드를 합산에서 제외하기 위한 파라미터 (null=create).
     * sumShareByContract는 계약 전체 합을 반환하므로, 수정 시 기존 자신의 share_rate를 차감.
     */
    private void validateShareRate(Long contractId, Long excludeJointId, BigDecimal newShareRate) {
        BigDecimal existingSum = jointContractMapper.sumShareByContract(contractId);
        if (existingSum == null) existingSum = BigDecimal.ZERO;

        if (excludeJointId != null) {
            JointContractResp existing = jointContractMapper.selectById(excludeJointId);
            if (existing != null) {
                existingSum = existingSum.subtract(existing.getShareRate());
            }
        }

        if (existingSum.add(newShareRate).compareTo(BigDecimal.ONE) > 0) {
            throw new BizException(ErrorCode.INVALID_PARAMETER, "계약별 지분율 합이 1을 초과합니다.");
        }
    }
}
