package com.jwipc.contract.logic.impl;

import com.jwipc.contract.entity.ContractSubSeq;
import com.jwipc.contract.logic.ContractSubSeqLogic;
import com.jwipc.contract.service.IContractSubSeqService;
import com.jwipc.exception.DaoException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 *  获取子合同编号接口实现类
 * </p>
 *
 * @author Chen Tianshi
 * @since 2026/1/15 11:46
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ContractSubSeqLogicImpl implements ContractSubSeqLogic {
    private final IContractSubSeqService contractSubSeqService;

    // 子合同编码长度
    private static final int SUFFIX_LEN = 3;

    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    @Override
    public String getRealSubContractCode(String parentContractCode) {
        // 1) 确保计数器行存在
        ensureSubSeqRowExists(parentContractCode);

        // 2) 行锁读取旧值
        Integer last = contractSubSeqService.selectByParentCodeForUpdate(parentContractCode);
        if (last == null) {
            throw new DaoException("子合同序号计数器异常");
        }

        // 3) 计算本次要用的序号
        int next = last + 1;

        // 4) 原子更新为 next（或 last_seq = last_seq + 1）
        int updated = contractSubSeqService.incrSeq(parentContractCode);
        if (updated != 1) {
            throw new DaoException("子合同序号更新失败");
        }

        return buildSubCode(parentContractCode, next);
    }

    @Override
    public String getTempSubContractCode(String parentContractCode) {
        Integer maxSeq = contractSubSeqService.selectMaxSubSeq(parentContractCode);
        int next = (maxSeq == null ? 1 : maxSeq + 1);

        return buildSubCode(parentContractCode, next);
    }

    /**
     * 初始化计数器行（使用唯一键冲突兜底）
     * @param parentContractCode 父合同编码
     */
    private void ensureSubSeqRowExists(String parentContractCode) {
        ContractSubSeq entity = new ContractSubSeq();
        entity.setParentContractCode(parentContractCode);
        entity.setLastSeq(0);
        try {
            contractSubSeqService.save(entity);
        } catch (Exception e) {
            if (!isDuplicateKey(e)) throw e;
        }
    }

    /**
     * 判断异常是否是唯一键冲突
     * @param e 异常
     * @return 是否是唯一键冲突
     */
    private boolean isDuplicateKey(Exception e) {
        Throwable t = e;
        while (t != null) {
            String name = t.getClass().getName();
            if (name.contains("DuplicateKeyException")
                    || name.contains("SQLIntegrityConstraintViolationException")) {
                return true;
            }
            t = t.getCause();
        }
        return false;
    }

    /**
     * 构建子合同编码
     * @param parentCode 父合同编码
     * @param seq 子合同序号
     * @return 子合同编码
     */
    private String buildSubCode(String parentCode, int seq) {
        return parentCode + "-" + String.format("%0" + SUFFIX_LEN + "d", seq);
    }
}
