package jnpf.certificate.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.seata.spring.annotation.GlobalTransactional;
import jnpf.base.ActionResult;
import jnpf.certificate.mapper.CertificateBusinessLicenseExtMapper;
import jnpf.certificate.mapper.CertificateHygieneLicenseExtMapper;
import jnpf.certificate.mapper.CertificateInstanceItemMapper;
import jnpf.certificate.mapper.CertificateInstanceMapper;
import jnpf.certificate.service.CertificateStoreService;
import jnpf.exception.HandleException;
import jnpf.model.certificate.po.CertificateBusinessLicenseExtEntity;
import jnpf.model.certificate.po.CertificateHygieneLicenseExtEntity;
import jnpf.model.certificate.po.CertificateInstanceEntity;
import jnpf.model.certificate.po.CertificateInstanceItemEntity;
import jnpf.model.certificate.req.CertificateInstanceItemReq;
import jnpf.model.certificate.req.CertificateStoreSaveReq;
import jnpf.model.certificate.req.app.CertificateAppBusinessLicenseUpdateReq;
import jnpf.model.certificate.req.app.CertificateAppHygieneLicenseUpdateReq;
import jnpf.model.certificate.req.app.CertificateAppStoreCustomUpdateReq;
import jnpf.model.certificate.vo.CertificateStoreAndCertificatesVO;
import jnpf.model.certificate.vo.CertificateStoreTabVO;
import jnpf.model.storecertificatephoto.po.StoreCertificatePhotoEntity;
import jnpf.model.storecertificatephoto.po.StoreCertificatePhotoItemEntity;
import jnpf.model.storecertificatephoto.vo.StoreCertificatePhotoItemVO;
import jnpf.model.storecertificatephoto.vo.StoreCertificatePhotoVO;
import jnpf.model.warningnotice.enums.CertificateTypeEnum;
import jnpf.permission.OrganizeApi;
import jnpf.permission.dto.v2.organzie.SaveStoreDTO;
import jnpf.storecertificatephoto.helper.StoreCertificatePhotoHelper;
import jnpf.storecertificatephoto.mapper.StoreCertificatePhotoItemMapper;
import jnpf.storecertificatephoto.mapper.StoreCertificatePhotoMapper;
import jnpf.util.FtbUtil;
import jnpf.util.ServiceException;
import jnpf.util.UserProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;

import java.sql.SQLIntegrityConstraintViolationException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 门店证照服务实现。
 */
@Slf4j
@Service
public class CertificateStoreServiceImpl implements CertificateStoreService {

    private static final int STATUS_MISSING = 1;
    private static final int STATUS_EXPIRED = 2;
    private static final int STATUS_NEAR_EXPIRE = 3;
    private static final int STATUS_NORMAL = 4;
    private static final int SUBJECT_TYPE_STORE = 3;
    private static final int NEAR_EXPIRE_DAYS = 30;

    @Autowired
    private OrganizeApi organizeApi;
    @Autowired
    private CertificateInstanceMapper certificateInstanceMapper;
    @Autowired
    private CertificateBusinessLicenseExtMapper certificateBusinessLicenseExtMapper;
    @Autowired
    private CertificateHygieneLicenseExtMapper certificateHygieneLicenseExtMapper;
    @Autowired
    private CertificateInstanceItemMapper certificateInstanceItemMapper;
    @Autowired
    private StoreCertificatePhotoMapper storeCertificatePhotoMapper;
    @Autowired
    private StoreCertificatePhotoItemMapper storeCertificatePhotoItemMapper;
    @Autowired
    private StoreCertificatePhotoHelper storeCertificatePhotoHelper;

    /**
     * 保存门店及门店证照。
     * 先调用组织服务保存门店，再保存证照实例及扩展表。
     */
    @Override
    public String saveStoreAndCertificates(CertificateStoreSaveReq req) {
        ServiceException.notNull(req, "请求参数不能为空");
        SaveStoreDTO store = req.getStore();
        ServiceException.notNull(store, "门店信息不能为空");
        validCustomerCertificates(req.getStoreCustomCertificates());

        String storeId = saveStore(store);
        saveBusinessLicense(storeId,store.getDisabled(), req.getBusinessLicense());
        saveHygieneLicense(storeId,store.getDisabled(), req.getHygieneLicense());
        saveStoreCustomCertificates(storeId, store.getDisabled(),req.getStoreCustomCertificates());
        return storeId;
    }

    private void validCustomerCertificates(Collection<CertificateAppStoreCustomUpdateReq> storeCustomCertificates) {
        if(CollectionUtil.isEmpty(storeCustomCertificates)){
            return;
        }
        for (CertificateAppStoreCustomUpdateReq req : storeCustomCertificates){
            ServiceException.notNull(req.getTemplateId(), "门店自定义证照模板id不能为空");
        }
    }

    @Override
    public boolean deleteStore(String id) throws HandleException {
        ActionResult<Boolean> actionResult = organizeApi.deleteStore(id);
        if(Objects.isNull(actionResult) || actionResult.getCode() != 200){
            log.error("deleteStore fail.id:{},actionResult:{}",id,actionResult);
            throw new HandleException("组织服务异常");
        }
        if(!actionResult.getData()){
            log.error("deleteStore organize fail.id:{}",id);
            throw new HandleException("删除失败!");
        }
        certificateInstanceMapper.update(new CertificateInstanceEntity(),new LambdaUpdateWrapper<CertificateInstanceEntity>()
                .eq(CertificateInstanceEntity::getSubjectId, id)
                .set(CertificateInstanceEntity::getEnabledMark,1));
        return true;
    }

    /**
     * 根据门店ID查询门店及门店证照详情。
     */
    @Override
    public CertificateStoreAndCertificatesVO getStoreAndCertificates(String storeId) {
        ServiceException.isTrue(StrUtil.isNotBlank(storeId), "门店ID不能为空");
        String targetStoreId = StrUtil.trim(storeId);

        CertificateStoreAndCertificatesVO result = new CertificateStoreAndCertificatesVO();
        result.setBusinessLicense(queryBusinessLicense(targetStoreId));
        result.setHygieneLicense(queryHygieneLicense(targetStoreId));
        result.setStoreCustomCertificates(queryStoreCustomCertificates(targetStoreId));
        return result;
    }

    @Override
    public List<CertificateStoreTabVO> queryStoreCertificateTabList() {
        List<CertificateStoreTabVO> result = new ArrayList<>();
        List<CertificateTypeEnum> defaultTypeList = Arrays.asList(
                CertificateTypeEnum.BUSINESS_LICENSE,
                CertificateTypeEnum.HYGIENE_LICENSE
        );
        for (CertificateTypeEnum certificateType : defaultTypeList) {
            CertificateStoreTabVO tabVO = new CertificateStoreTabVO();
            tabVO.setLabel(certificateType.getLabel());
            tabVO.setKey(certificateType.getType());
            tabVO.setType(certificateType.getType());
            result.add(tabVO);
        }

        List<StoreCertificatePhotoVO> templateList = queryStoreCustomTemplateList(1);
        if (CollUtil.isEmpty(templateList)) {
            return result;
        }
        for (StoreCertificatePhotoVO template : templateList) {
            if (template == null || StrUtil.isBlank(template.getId()) || StrUtil.isBlank(template.getCertificateName())) {
                continue;
            }
            CertificateStoreTabVO tabVO = new CertificateStoreTabVO();
            tabVO.setLabel(StrUtil.trim(template.getCertificateName()));
            tabVO.setKey(StrUtil.trim(template.getId()));
            tabVO.setType(CertificateTypeEnum.STORE_CUSTOM_CERTIFICATE.getType());
            tabVO.setStoreCustomConfig(template);
            result.add(tabVO);
        }
        return result;
    }

    /**
     * 调用组织服务保存门店并返回门店ID。
     */
    private String saveStore(SaveStoreDTO storeDTO) {
        ActionResult<String> actionResult;
        try {
            actionResult = organizeApi.saveStore(storeDTO);
        } catch (Exception e) {
            throw new ServiceException("保存门店失败: " + e.getMessage());
        }
        ServiceException.notNull(actionResult, "保存门店失败");
        ServiceException.isTrue(ActionResult.success().getCode().equals(actionResult.getCode()),
                StrUtil.blankToDefault(actionResult.getMsg(), "保存门店失败"));
        String storeId = StrUtil.trim(actionResult.getData());
        if (StrUtil.isBlank(storeId)) {
            storeId = StrUtil.trim(storeDTO.getId());
        }
        ServiceException.isTrue(StrUtil.isNotBlank(storeId), "保存门店成功但未返回门店ID");
        return storeId;
    }

    /**
     * 批量查询启用中的门店自定义证照模板及明细。
     */
    private List<StoreCertificatePhotoVO> queryStoreCustomTemplateList(Integer status) {
        LambdaQueryWrapper<StoreCertificatePhotoEntity> templateWrapper = Wrappers.lambdaQuery();
        templateWrapper.eq(StoreCertificatePhotoEntity::getEnabledMark, 0);
        if(Objects.nonNull(status)){
            templateWrapper.eq(StoreCertificatePhotoEntity::getStatus, status);
        }
        templateWrapper.orderByDesc(StoreCertificatePhotoEntity::getCreatorTime);
        List<StoreCertificatePhotoEntity> templateEntities = storeCertificatePhotoMapper.selectList(templateWrapper);
        if (CollUtil.isEmpty(templateEntities)) {
            return Collections.emptyList();
        }

        List<String> templateIds = templateEntities.stream()
                .map(StoreCertificatePhotoEntity::getId)
                .filter(StrUtil::isNotBlank)
                .map(StrUtil::trim)
                .collect(Collectors.toList());
        Map<String, List<StoreCertificatePhotoItemEntity>> itemMap = queryStoreCustomTemplateItemMap(templateIds);
        return templateEntities.stream()
                .map(entity -> buildStoreCustomTemplateVO(entity, itemMap))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 按模板ID列表查询模板明细并按模板分组。
     */
    private Map<String, List<StoreCertificatePhotoItemEntity>> queryStoreCustomTemplateItemMap(List<String> templateIds) {
        if (CollUtil.isEmpty(templateIds)) {
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<StoreCertificatePhotoItemEntity> itemWrapper = Wrappers.lambdaQuery();
        itemWrapper.in(StoreCertificatePhotoItemEntity::getPhotoId, templateIds);
        itemWrapper.eq(StoreCertificatePhotoItemEntity::getEnabledMark, 0);
        itemWrapper.orderByAsc(StoreCertificatePhotoItemEntity::getPhotoId)
                .orderByAsc(StoreCertificatePhotoItemEntity::getItemType)
                .orderByAsc(StoreCertificatePhotoItemEntity::getSorts);
        List<StoreCertificatePhotoItemEntity> itemEntities = storeCertificatePhotoItemMapper.selectList(itemWrapper);
        if (CollUtil.isEmpty(itemEntities)) {
            return Collections.emptyMap();
        }
        return itemEntities.stream().collect(Collectors.groupingBy(StoreCertificatePhotoItemEntity::getPhotoId));
    }

    /**
     * 构建门店自定义证照模板返回对象。
     */
    private StoreCertificatePhotoVO buildStoreCustomTemplateVO(StoreCertificatePhotoEntity entity,
                                                               Map<String, List<StoreCertificatePhotoItemEntity>> itemMap) {
        if (entity == null || StrUtil.isBlank(entity.getId())) {
            return null;
        }
        StoreCertificatePhotoVO vo = StoreCertificatePhotoVO.convert(entity);
        List<StoreCertificatePhotoItemEntity> itemEntities = itemMap.getOrDefault(entity.getId(), Collections.emptyList());
        List<StoreCertificatePhotoItemVO> imageItemList = new ArrayList<>();
        List<StoreCertificatePhotoItemVO> textItemList = new ArrayList<>();
        for (StoreCertificatePhotoItemEntity itemEntity : itemEntities) {
            StoreCertificatePhotoItemVO itemVO = StoreCertificatePhotoItemVO.convert(itemEntity);
            if (itemVO == null) {
                continue;
            }
            if (Integer.valueOf(1).equals(itemEntity.getItemType())) {
                imageItemList.add(itemVO);
                continue;
            }
            if (Integer.valueOf(2).equals(itemEntity.getItemType())) {
                textItemList.add(itemVO);
            }
        }
        imageItemList.sort(Comparator.comparing(item -> item.getSorts() == null ? Long.MAX_VALUE : item.getSorts()));
        textItemList.sort(Comparator.comparing(item -> item.getSorts() == null ? Long.MAX_VALUE : item.getSorts()));
        vo.setImageItemList(imageItemList);
        vo.setTextItemList(textItemList);
        return vo;
    }

    /**
     * 保存营业执照实例和扩展数据。
     */
    private void saveBusinessLicense(String storeId,Integer disable, CertificateAppBusinessLicenseUpdateReq req) {
        if (req == null) {
            req = new CertificateAppBusinessLicenseUpdateReq();
        }
        CertificateInstanceEntity instance = findOrCreateSingleInstance(
                storeId,
                req.getCertificateInstanceId(),
                CertificateTypeEnum.BUSINESS_LICENSE.getType()
        );
        Date issueDate = parseDate(req.getIssueDate(), "营业执照发证日期");
        Date expireDate = parseDate(req.getExpireDate(), "营业执照到期日期");
        Date establishDate = parseDate(req.getEstablishDate(), "营业执照成立时间");
        Integer isLongTerm = req.getIsLongTerm() == null ? 0 : req.getIsLongTerm();
        if (Integer.valueOf(1).equals(isLongTerm)) {
            expireDate = null;
        }

        instance.setIssueDate(issueDate);
        instance.setExpireDate(expireDate);
        if(Objects.nonNull(expireDate)){
            instance.setExpireTimestamp(expireDate.getTime());
        }else{
            instance.setExpireTimestamp(0);
        }
        instance.setIsLongTerm(isLongTerm);
        instance.setCertificateNo(trimToNull(req.getCertificateNo()));
        instance.setCertificateImage(trimToNull(req.getCertificateImage()));
        instance.setStatus(calculateStatus(instance.getIsLongTerm(), instance.getExpireDate()));
        instance.setStoreDisable(buildStoreDisable(disable));
        saveOrUpdateInstance(instance);

        upsertBusinessLicenseExt(instance.getId(), req, establishDate);
    }

    private Integer buildStoreDisable(Integer disable) {
        if(Objects.isNull(disable)){
            return 0;
        }
        return disable == 1?1:0;
    }

    /**
     * 查询门店营业执照详情。
     */
    private CertificateAppBusinessLicenseUpdateReq queryBusinessLicense(String storeId) {
        CertificateInstanceEntity instance = findLatestByStoreAndType(storeId, CertificateTypeEnum.BUSINESS_LICENSE.getType(),null);
        if (instance == null) {
            return null;
        }
        CertificateBusinessLicenseExtEntity extEntity = findBusinessExt(instance.getId());
        CertificateAppBusinessLicenseUpdateReq result = new CertificateAppBusinessLicenseUpdateReq();
        result.setCertificateInstanceId(instance.getId());
        result.setCertificateImage(instance.getCertificateImage());
        result.setCertificateNo(instance.getCertificateNo());
        result.setIssueDate(formatDate(instance.getIssueDate()));
        result.setExpireDate(formatDate(instance.getExpireDate()));
        result.setIsLongTerm(instance.getIsLongTerm() == null ? 0 : instance.getIsLongTerm());
        if (extEntity != null) {
            result.setCompanyName(extEntity.getCompanyName());
            result.setLegalRepresentative(extEntity.getLegalRepresentative());
            result.setEstablishDate(formatDate(extEntity.getEstablishDate()));
            result.setBusinessScope(extEntity.getBusinessScope());
            result.setAddress(extEntity.getCompanyAddress());
        }
        return result;
    }

    /**
     * 保存食品经营许可证实例和扩展数据。
     */
    private void saveHygieneLicense(String storeId, Integer storeDisable,CertificateAppHygieneLicenseUpdateReq req) {
        if (req == null) {
            req = new CertificateAppHygieneLicenseUpdateReq();
        }
        CertificateInstanceEntity instance = findOrCreateSingleInstance(
                storeId,
                req.getCertificateInstanceId(),
                CertificateTypeEnum.HYGIENE_LICENSE.getType()
        );
        Date issueDate = parseDate(req.getIssueDate(), "食品经营许可证发证日期");
        Date expireDate = parseDate(req.getExpireDate(), "食品经营许可证到期日期");

        instance.setIssueDate(issueDate);
        instance.setExpireDate(expireDate);
        if(Objects.nonNull(expireDate)){
            instance.setExpireTimestamp(expireDate.getTime());
        }
        instance.setIsLongTerm(0);
        instance.setCertificateImage(trimToNull(req.getCertificateImage()));
        instance.setStatus(calculateStatus(instance.getIsLongTerm(), instance.getExpireDate()));
        instance.setStoreDisable(buildStoreDisable(storeDisable));
        saveOrUpdateInstance(instance);

        upsertHygieneLicenseExt(instance.getId(), req);
    }

    /**
     * 查询门店食品经营许可证详情。
     */
    private CertificateAppHygieneLicenseUpdateReq queryHygieneLicense(String storeId) {
        CertificateInstanceEntity instance = findLatestByStoreAndType(storeId, CertificateTypeEnum.HYGIENE_LICENSE.getType(),null);
        if (instance == null) {
            return null;
        }
        CertificateHygieneLicenseExtEntity extEntity = findHygieneExt(instance.getId());
        CertificateAppHygieneLicenseUpdateReq result = new CertificateAppHygieneLicenseUpdateReq();
        result.setCertificateInstanceId(instance.getId());
        result.setCertificateImage(instance.getCertificateImage());
        result.setIssueDate(formatDate(instance.getIssueDate()));
        result.setExpireDate(formatDate(instance.getExpireDate()));
        if (extEntity != null) {
            result.setBusinessProject(extEntity.getBusinessProject());
        }
        return result;
    }

    /**
     * 保存门店自定义证照实例和明细数据。
     */
    private void saveStoreCustomCertificates(String storeId,Integer disabled, Collection<CertificateAppStoreCustomUpdateReq> reqList) {
        if (CollUtil.isEmpty(reqList)) {
            return;
        }

        Map<String,String> templateNameById = storeCertificatePhotoHelper.buildStoreCertificateIdAndNames(reqList.stream()
                        .map(CertificateAppStoreCustomUpdateReq::getTemplateId)
                .collect(Collectors.toSet()),1);
        for (CertificateAppStoreCustomUpdateReq req : reqList) {
            if (req == null) {
                continue;
            }

            //如果是禁用状态，则跳过
            String templateId = req.getTemplateId();
            int templateStatus = 1;
            if(!templateNameById.containsKey(templateId)){
                templateStatus = 0;
                continue;
            }
            CertificateInstanceEntity instance = findOrCreateCustomInstance(storeId, req.getCertificateInstanceId(), templateId);

            Date expireDate = parseDate(req.getExpireDate(), "门店自定义证照到期日期");

            instance.setCertificateImage(buildCustomCertificateImage(req.getItemList()));
            instance.setIssueDate(null);
            instance.setExpireDate(expireDate);
            if(Objects.nonNull(expireDate)){
                instance.setExpireTimestamp(expireDate.getTime());
            }
            instance.setIsLongTerm(0);
            instance.setStatus(calculateStatus(instance.getIsLongTerm(), instance.getExpireDate()));

            instance.setTemplateStatus(templateStatus);
            instance.setStoreDisable(buildStoreDisable(disabled));
            saveOrUpdateInstance(instance);

            rewriteCustomItems(instance.getId(), req.getItemList());
        }
    }

    private String buildCustomCertificateImage(List<CertificateInstanceItemReq> itemList) {
        if(CollectionUtil.isEmpty(itemList)){
            return "";
        }
        for (CertificateInstanceItemReq item : itemList) {
            if (item == null) {
                continue;
            }
            if (item.getItemType() == 1) {
                return item.getItemValue();
            }
        }
        return "";
    }

    /**
     * 查询门店自定义证照详情集合。
     */
    private List<CertificateAppStoreCustomUpdateReq> queryStoreCustomCertificates(String storeId) {
        LambdaQueryWrapper<CertificateInstanceEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CertificateInstanceEntity::getEnabledMark, 0);
        wrapper.eq(CertificateInstanceEntity::getSubjectType, SUBJECT_TYPE_STORE);
        wrapper.eq(CertificateInstanceEntity::getSubjectId, storeId);
        wrapper.eq(CertificateInstanceEntity::getCertificateType, CertificateTypeEnum.STORE_CUSTOM_CERTIFICATE.getType());
        wrapper.orderByDesc(CertificateInstanceEntity::getLastModifyTime);
        wrapper.orderByDesc(CertificateInstanceEntity::getCreatorTime);
        List<CertificateInstanceEntity> instanceList = certificateInstanceMapper.selectList(wrapper);
        if (CollUtil.isEmpty(instanceList)) {
            return Collections.emptyList();
        }

        Set<String> enabledTemplateIds = storeCertificatePhotoMapper.selectList(new LambdaQueryWrapper<StoreCertificatePhotoEntity>()
                        .select(StoreCertificatePhotoEntity::getId)
                        .in(StoreCertificatePhotoEntity::getId,instanceList.stream()
                                .map(CertificateInstanceEntity::getTemplateId)
                                .collect(Collectors.toSet()))
                        .eq(StoreCertificatePhotoEntity::getEnabledMark,0)
                        .eq(StoreCertificatePhotoEntity::getStatus,1))
                .stream()
                .map(StoreCertificatePhotoEntity::getId)
                .collect(Collectors.toSet());

        Map<String, List<CertificateInstanceItemEntity>> itemMap = queryStoreCustomItemMap(instanceList.stream()
                .filter(instance->{
                    String templateId = instance.getTemplateId();
                    if(StringUtils.isBlank(templateId)){
                        return true;
                    }
                    return enabledTemplateIds.contains(templateId);
                })
                .map(CertificateInstanceEntity::getId)
                .collect(Collectors.toSet()));
        return instanceList.stream()
                .filter(instance->{
                    String templateId = instance.getTemplateId();
                    if(StringUtils.isBlank(templateId)){
                        return true;
                    }
                    return enabledTemplateIds.contains(templateId);
                })
                .map(instance -> convertStoreCustomCertificate(instance, itemMap))
                .collect(Collectors.toList());
    }

    /**
     * 按证照实例ID批量查询自定义证照明细并分组。
     */
    private Map<String, List<CertificateInstanceItemEntity>> queryStoreCustomItemMap(Collection<String> instanceIds) {
        if (CollUtil.isEmpty(instanceIds)) {
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<CertificateInstanceItemEntity> itemWrapper = Wrappers.lambdaQuery();
        itemWrapper.in(CertificateInstanceItemEntity::getInstanceId, instanceIds);
        itemWrapper.eq(CertificateInstanceItemEntity::getEnabledMark, 0);
        itemWrapper.orderByAsc(CertificateInstanceItemEntity::getInstanceId);
        itemWrapper.orderByAsc(CertificateInstanceItemEntity::getSorts);
        List<CertificateInstanceItemEntity> itemEntities = certificateInstanceItemMapper.selectList(itemWrapper);
        if (CollUtil.isEmpty(itemEntities)) {
            return Collections.emptyMap();
        }

        return itemEntities.stream()
                .collect(Collectors.groupingBy(CertificateInstanceItemEntity::getInstanceId));
    }

    /**
     * 根据证照实例ID或门店+证照类型查询单条实例，不存在则创建。
     */
    private CertificateInstanceEntity findOrCreateSingleInstance(String storeId, String certificateInstanceId, String certificateType) {
        CertificateInstanceEntity instance = findByInstanceId(certificateInstanceId, certificateType);
        if (instance == null) {
            instance = findLatestByStoreAndType(storeId, certificateType,null);
        }
        if (instance == null) {
            instance = createNewInstance(storeId, certificateType);
        }
        normalizeStoreInstance(instance, storeId, certificateType);
        return instance;
    }

    /**
     * 根据证照实例ID查询自定义证照实例，不存在则创建新实例。
     */
    private CertificateInstanceEntity findOrCreateCustomInstance(String storeId, String certificateInstanceId, String templateId) {
        String certificateType = CertificateTypeEnum.STORE_CUSTOM_CERTIFICATE.getType();
        CertificateInstanceEntity instance = findByInstanceId(certificateInstanceId, certificateType);
        if (instance == null) {
            instance = createNewInstance(storeId, certificateType);
            instance.setTemplateId(templateId);
        }
        normalizeStoreInstance(instance, storeId, certificateType);
        return instance;
    }

    /**
     * 按证照实例ID查询。
     */
    private CertificateInstanceEntity findByInstanceId(String certificateInstanceId, String certificateType) {
        if (StrUtil.isBlank(certificateInstanceId)) {
            return null;
        }
        String instanceId = StrUtil.trim(certificateInstanceId);
        CertificateInstanceEntity instance = certificateInstanceMapper.selectById(instanceId);
        ServiceException.isTrue(instance != null && Integer.valueOf(0).equals(instance.getEnabledMark()), "证照实例不存在");
        ServiceException.isTrue(StrUtil.equalsIgnoreCase(StrUtil.trim(instance.getCertificateType()), certificateType), "证照类型不匹配");
        return instance;
    }

    /**
     * 按门店和证照类型查询最新实例。
     */
    private CertificateInstanceEntity findLatestByStoreAndType(String storeId, String certificateType,String templateId) {
        LambdaQueryWrapper<CertificateInstanceEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CertificateInstanceEntity::getEnabledMark, 0);
        wrapper.eq(CertificateInstanceEntity::getSubjectType, SUBJECT_TYPE_STORE);
        wrapper.eq(CertificateInstanceEntity::getSubjectId, storeId);
        wrapper.eq(CertificateInstanceEntity::getCertificateType, certificateType);
        if(StringUtils.isNotBlank(templateId)){
            wrapper.eq(CertificateInstanceEntity::getTemplateId, templateId);
        }
        wrapper.orderByDesc(CertificateInstanceEntity::getLastModifyTime);
        wrapper.orderByDesc(CertificateInstanceEntity::getCreatorTime);
        List<CertificateInstanceEntity> list = certificateInstanceMapper.selectList(wrapper);
        return CollUtil.isEmpty(list) ? null : list.get(0);
    }

    /**
     * 构建新证照实例。
     */
    private CertificateInstanceEntity createNewInstance(String storeId, String certificateType) {
        CertificateInstanceEntity instance = new CertificateInstanceEntity();
        instance.setSubjectType(SUBJECT_TYPE_STORE);
        instance.setSubjectId(storeId);
        instance.setCertificateType(certificateType);
        instance.setEnabledMark(0);
        instance.setTemplateId("");
        instance.setCreatorUserId(UserProvider.getLoginUserId());
        instance.setCreatorTime(new Date());
        instance.setLastModifyUserId(UserProvider.getLoginUserId());
        instance.setLastModifyTime(new Date());
        return instance;
    }

    /**
     * 规范化门店证照实例字段。
     */
    private void normalizeStoreInstance(CertificateInstanceEntity instance, String storeId, String certificateType) {
        instance.setSubjectType(SUBJECT_TYPE_STORE);
        instance.setSubjectId(storeId);
        instance.setCertificateType(certificateType);
        if (instance.getEnabledMark() == null) {
            instance.setEnabledMark(0);
        }
    }

    /**
     * 保存或更新证照实例。
     */
    private void saveOrUpdateInstance(CertificateInstanceEntity instance) {
        if(StringUtils.isNotBlank(instance.getId())){
            updateInstanceByWrapper(instance);
            return;
        }
        instance.setId(FtbUtil.getId());
        try {
            certificateInstanceMapper.insert(instance);
        } catch (DuplicateKeyException e) {
            updateInstance(instance);
        } catch (DataIntegrityViolationException e) {
            if (isDuplicateKeyException(e)) {
                updateInstance(instance);
                return;
            }
            throw e;
        } catch (Exception e) {
            if (isDuplicateKeyException(e)) {
                updateInstance(instance);
                return;
            }
            throw e;
        }
//        catch (SQLIntegrityConstraintViolationException e){
//            String msg = e.getMessage();
//            if (msg.contains("Duplicate entry")){
//                updateInstance(instance);
//                return;
//            }
//            throw e;
//        }
    }

    /**
     * 判断异常链中是否包含唯一键冲突。
     * 兼容 Seata/MyBatis 对 JDBC 异常的包装场景。
     */
    private boolean isDuplicateKeyException(Throwable throwable) {
        Throwable current = throwable;
        while (current != null) {
            if (current instanceof DuplicateKeyException || current instanceof SQLIntegrityConstraintViolationException) {
                return true;
            }
            String message = current.getMessage();
            if (StringUtils.isNotBlank(message)
                    && StringUtils.containsIgnoreCase(message, "Duplicate entry")
                    && StringUtils.containsIgnoreCase(message, "for key")) {
                return true;
            }
            current = current.getCause();
        }
        return false;
    }

    private void updateInstance(CertificateInstanceEntity instance) {
        if(Objects.isNull(instance)){
            return;
        }
        CertificateInstanceEntity dbInstance = findLatestByStoreAndType(instance.getSubjectId(), instance.getCertificateType(),instance.getTemplateId());
        if(Objects.isNull(dbInstance)){
            log.error("updateInstance fail.findLatestByStoreAndType null.instance:{}",instance);
            return;
        }
        instance.setId(dbInstance.getId());
        updateInstanceByWrapper(instance);
    }

    private void updateInstanceByWrapper(CertificateInstanceEntity instance) {
        LambdaUpdateWrapper<CertificateInstanceEntity> updateWrapper = new LambdaUpdateWrapper<CertificateInstanceEntity>().eq(CertificateInstanceEntity::getId,instance.getId())
                .set(CertificateInstanceEntity::getCertificateImage, instance.getCertificateImage())
                .set(CertificateInstanceEntity::getIssueDate, instance.getIssueDate())
                .set(CertificateInstanceEntity::getExpireDate, instance.getExpireDate())
                .set(CertificateInstanceEntity::getExpireTimestamp, instance.getExpireTimestamp())
                .set(CertificateInstanceEntity::getStatus, instance.getStatus())
                .set(CertificateInstanceEntity::getLastModifyTime, instance.getLastModifyTime())
                .set(CertificateInstanceEntity::getLastModifyUserId, instance.getLastModifyUserId())
                .set(CertificateInstanceEntity::getEnabledMark, instance.getEnabledMark())
                .set(CertificateInstanceEntity::getCreatorTime, instance.getCreatorTime())
                .set(CertificateInstanceEntity::getCreatorUserId, instance.getCreatorUserId())
                .set(CertificateInstanceEntity::getStoreDisable,instance.getStoreDisable());
        Integer templateStatus = instance.getTemplateStatus();
        if(Objects.nonNull(templateStatus)){
            updateWrapper.set(CertificateInstanceEntity::getTemplateStatus,templateStatus);
        }
        int r = certificateInstanceMapper.update(null,updateWrapper);
        if(r<=0){
            log.error("saveOrUpdateInstance insert fail.update also fail.instance:{}",instance);
        }
    }

    /**
     * 保存营业执照扩展表。
     */
    private void upsertBusinessLicenseExt(String instanceId, CertificateAppBusinessLicenseUpdateReq req, Date establishDate) {
        CertificateBusinessLicenseExtEntity extEntity = new CertificateBusinessLicenseExtEntity();
        extEntity.setId(FtbUtil.getId());
        extEntity.setInstanceId(instanceId);
        extEntity.setEnabledMark(0);
        fillBusinessExt(extEntity, req, establishDate);
        try {
            certificateBusinessLicenseExtMapper.insert(extEntity);
        }catch (DuplicateKeyException e){
            int r = certificateBusinessLicenseExtMapper.update(null,new LambdaUpdateWrapper<CertificateBusinessLicenseExtEntity>()
                    .eq(CertificateBusinessLicenseExtEntity::getInstanceId,instanceId)
                    .eq(CertificateBusinessLicenseExtEntity::getEnabledMark,0)
                    .set(CertificateBusinessLicenseExtEntity::getCompanyName,extEntity.getCompanyName())
                    .set(CertificateBusinessLicenseExtEntity::getCompanyAddress,extEntity.getCompanyAddress())
                    .set(CertificateBusinessLicenseExtEntity::getLegalRepresentative,extEntity.getLegalRepresentative())
                    .set(CertificateBusinessLicenseExtEntity::getEstablishDate,extEntity.getEstablishDate())
                    .set(CertificateBusinessLicenseExtEntity::getBusinessScope,extEntity.getBusinessScope())
                    .set(CertificateBusinessLicenseExtEntity::getCreatorTime,extEntity.getCreatorTime())
                    .set(CertificateBusinessLicenseExtEntity::getCreatorUserId,extEntity.getCreatorUserId())
                    .set(CertificateBusinessLicenseExtEntity::getLastModifyTime,extEntity.getLastModifyTime())
                    .set(CertificateBusinessLicenseExtEntity::getLastModifyUserId,extEntity.getLastModifyUserId())
            );
            if(r <= 0){
                log.error("upsertBusinessLicenseExt insert fail.update row count is:{}.instanceId:{},extEntity:{}",r,instanceId,extEntity);
            }
        }
    }

    /**
     * 保存食品经营许可证扩展表。
     */
    private void upsertHygieneLicenseExt(String instanceId, CertificateAppHygieneLicenseUpdateReq req) {
        CertificateHygieneLicenseExtEntity extEntity = findHygieneExt(instanceId);
        if (extEntity == null) {
            extEntity = new CertificateHygieneLicenseExtEntity();
            extEntity.setId(FtbUtil.getId());
            extEntity.setInstanceId(instanceId);
            extEntity.setEnabledMark(0);
            extEntity.setBusinessProject(trimToNull(req.getBusinessProject()));
            certificateHygieneLicenseExtMapper.insert(extEntity);
            return;
        }
        extEntity.setBusinessProject(trimToNull(req.getBusinessProject()));
        certificateHygieneLicenseExtMapper.updateById(extEntity);
    }

    /**
     * 重写门店自定义证照明细。
     */
    private void rewriteCustomItems(String instanceId, List<CertificateInstanceItemReq> itemList) {
        LambdaQueryWrapper<CertificateInstanceItemEntity> deleteWrapper = Wrappers.lambdaQuery();
        deleteWrapper.eq(CertificateInstanceItemEntity::getInstanceId, instanceId);
        certificateInstanceItemMapper.delete(deleteWrapper);

        List<CertificateInstanceItemReq> safeItemList = itemList == null ? Collections.emptyList() : itemList;
        long sort = 1L;
        for (CertificateInstanceItemReq itemReq : safeItemList) {
            if (itemReq == null || StrUtil.isBlank(itemReq.getItemName())) {
                continue;
            }
            CertificateInstanceItemEntity itemEntity = new CertificateInstanceItemEntity();
            itemEntity.setId(FtbUtil.getId());
            itemEntity.setInstanceId(instanceId);
            itemEntity.setTemplateItemId(trimToNull(itemReq.getTemplateItemId()));
            itemEntity.setItemName(trimToNull(itemReq.getItemName()));
            itemEntity.setItemType(itemReq.getItemType());
            itemEntity.setItemValue(trimToNull(itemReq.getItemValue()));
            itemEntity.setSorts(itemReq.getSorts() == null ? sort : itemReq.getSorts());
            itemEntity.setEnabledMark(0);
            certificateInstanceItemMapper.insert(itemEntity);
            sort++;
        }
    }

    /**
     * 查询营业执照扩展数据。
     */
    private CertificateBusinessLicenseExtEntity findBusinessExt(String instanceId) {
        LambdaQueryWrapper<CertificateBusinessLicenseExtEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CertificateBusinessLicenseExtEntity::getInstanceId, instanceId);
        wrapper.eq(CertificateBusinessLicenseExtEntity::getEnabledMark, 0);
        wrapper.orderByDesc(CertificateBusinessLicenseExtEntity::getLastModifyTime);
        wrapper.orderByDesc(CertificateBusinessLicenseExtEntity::getCreatorTime);
        List<CertificateBusinessLicenseExtEntity> extList = certificateBusinessLicenseExtMapper.selectList(wrapper);
        return CollUtil.isEmpty(extList) ? null : extList.get(0);
    }

    /**
     * 查询食品经营许可证扩展数据。
     */
    private CertificateHygieneLicenseExtEntity findHygieneExt(String instanceId) {
        LambdaQueryWrapper<CertificateHygieneLicenseExtEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CertificateHygieneLicenseExtEntity::getInstanceId, instanceId);
        wrapper.eq(CertificateHygieneLicenseExtEntity::getEnabledMark, 0);
        wrapper.orderByDesc(CertificateHygieneLicenseExtEntity::getLastModifyTime);
        wrapper.orderByDesc(CertificateHygieneLicenseExtEntity::getCreatorTime);
        List<CertificateHygieneLicenseExtEntity> extList = certificateHygieneLicenseExtMapper.selectList(wrapper);
        return CollUtil.isEmpty(extList) ? null : extList.get(0);
    }

    /**
     * 将自定义证照实例转换为查询返回对象。
     */
    private CertificateAppStoreCustomUpdateReq convertStoreCustomCertificate(
            CertificateInstanceEntity instance,
            Map<String, List<CertificateInstanceItemEntity>> itemMap) {
        CertificateAppStoreCustomUpdateReq result = new CertificateAppStoreCustomUpdateReq();
        result.setCertificateInstanceId(instance.getId());
        result.setExpireDate(formatDate(instance.getExpireDate()));
        result.setTemplateId(instance.getTemplateId());

        List<CertificateInstanceItemEntity> itemEntities = itemMap.getOrDefault(instance.getId(), Collections.emptyList());
        if (CollUtil.isEmpty(itemEntities)) {
            return result;
        }
        result.setItemList(itemEntities.stream().map(entity -> {
            CertificateInstanceItemReq itemReq = new CertificateInstanceItemReq();
            itemReq.setTemplateItemId(entity.getTemplateItemId());
            itemReq.setItemName(entity.getItemName());
            itemReq.setItemType(entity.getItemType());
            itemReq.setItemValue(entity.getItemValue());
            itemReq.setSorts(entity.getSorts());
            return itemReq;
        }).filter(Objects::nonNull).collect(Collectors.toList()));
        return result;
    }

    /**
     * 填充营业执照扩展字段。
     */
    private void fillBusinessExt(CertificateBusinessLicenseExtEntity extEntity, CertificateAppBusinessLicenseUpdateReq req, Date establishDate) {
        extEntity.setCompanyName(trimToNull(req.getCompanyName()));
        extEntity.setLegalRepresentative(trimToNull(req.getLegalRepresentative()));
        extEntity.setEstablishDate(establishDate);
        extEntity.setBusinessScope(trimToNull(req.getBusinessScope()));
        extEntity.setCompanyAddress(req.getAddress());
        extEntity.setCreatorTime(new Date());
        extEntity.setCreatorUserId(UserProvider.getLoginUserId());
        extEntity.setLastModifyTime(new Date());
        extEntity.setLastModifyUserId(UserProvider.getLoginUserId());
    }

    /**
     * 解析日期文本，格式为 yyyy-MM-dd。
     */
    private Date parseDate(String dateText, String fieldName) {
        if (StrUtil.isBlank(dateText)) {
            return null;
        }
        try {
            return DateUtil.parseDate(StrUtil.trim(dateText));
        } catch (Exception e) {
            throw new ServiceException(fieldName + "格式不正确，正确格式为yyyy-MM-dd");
        }
    }

    /**
     * 日期格式化为 yyyy-MM-dd 字符串。
     */
    private String formatDate(Date date) {
        if (date == null) {
            return null;
        }
        return DateUtil.formatDate(date);
    }

    /**
     * 根据结束时间计算证照状态。
     */
    private Integer calculateStatus(Integer isLongTerm, Date expireDate) {
        if (Integer.valueOf(1).equals(isLongTerm)) {
            return STATUS_NORMAL;
        }
        if (expireDate == null) {
            return STATUS_MISSING;
        }
        Date today = DateUtil.beginOfDay(DateUtil.date());
        Date target = DateUtil.beginOfDay(expireDate);
        if (target.before(today)) {
            return STATUS_EXPIRED;
        }
        long daysDiff = DateUtil.betweenDay(today, target, false);
        if (daysDiff <= NEAR_EXPIRE_DAYS) {
            return STATUS_NEAR_EXPIRE;
        }
        return STATUS_NORMAL;
    }

    /**
     * 字符串去首尾空格，空串转为null。
     */
    private String trimToNull(String value) {
        String trimValue = StrUtil.trim(value);
        return StrUtil.isBlank(trimValue) ? null : trimValue;
    }
}
