package com.ruoyi.info.collection.service.support;

import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.info.collection.domain.CcdiEnterpriseBaseInfo;
import com.ruoyi.info.collection.enums.EnterpriseSource;
import com.ruoyi.info.collection.mapper.CcdiEnterpriseBaseInfoMapper;
import jakarta.annotation.Resource;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 关联业务实体库自动补全服务。
 */
@Service
public class EnterpriseAutoFillService {

    private static final int BATCH_SIZE = 500;

    @Resource
    private CcdiEnterpriseBaseInfoMapper enterpriseBaseInfoMapper;

    public record EnterpriseFillItem(
        String socialCreditCode,
        String enterpriseName,
        String entSource,
        String dataSource,
        String userName
    ) {
    }

    @Transactional
    public void ensureExists(EnterpriseFillItem item) {
        ensureExistsBatch(List.of(item));
    }

    @Transactional
    public void ensureExistsBatch(List<EnterpriseFillItem> items) {
        if (StringUtils.isEmpty(items)) {
            return;
        }
        Map<String, EnterpriseFillItem> normalizedItems = normalizeItems(items);
        if (normalizedItems.isEmpty()) {
            return;
        }

        Set<String> existingCodes = enterpriseBaseInfoMapper.selectBatchIds(new ArrayList<>(normalizedItems.keySet()))
            .stream()
            .map(CcdiEnterpriseBaseInfo::getSocialCreditCode)
            .collect(Collectors.toSet());
        List<CcdiEnterpriseBaseInfo> missingEntities = normalizedItems.entrySet().stream()
            .filter(entry -> !existingCodes.contains(entry.getKey()))
            .map(entry -> buildEntity(entry.getKey(), entry.getValue()))
            .toList();
        if (missingEntities.isEmpty()) {
            return;
        }
        insertBatchIgnoreDuplicate(missingEntities);
    }

    private Map<String, EnterpriseFillItem> normalizeItems(List<EnterpriseFillItem> items) {
        Map<String, EnterpriseFillItem> normalizedItems = new LinkedHashMap<>();
        for (EnterpriseFillItem item : items) {
            if (item == null || StringUtils.isEmpty(item.socialCreditCode())) {
                continue;
            }
            String socialCreditCode = item.socialCreditCode().trim();
            normalizedItems.putIfAbsent(socialCreditCode, new EnterpriseFillItem(
                socialCreditCode,
                trimToNull(item.enterpriseName()),
                trimToNull(item.entSource()),
                trimToNull(item.dataSource()),
                trimToNull(item.userName())
            ));
        }
        return normalizedItems;
    }

    private CcdiEnterpriseBaseInfo buildEntity(String socialCreditCode, EnterpriseFillItem item) {
        CcdiEnterpriseBaseInfo entity = new CcdiEnterpriseBaseInfo();
        entity.setSocialCreditCode(socialCreditCode);
        entity.setEnterpriseName(item.enterpriseName());
        entity.setEntSource(item.entSource());
        entity.setDataSource(item.dataSource());
        entity.setRiskLevel(EnterpriseSource.INTERMEDIARY.getCode().equals(item.entSource()) ? "1" : null);
        entity.setCreatedBy(item.userName());
        entity.setUpdatedBy(item.userName());
        return entity;
    }

    private void insertBatchIgnoreDuplicate(List<CcdiEnterpriseBaseInfo> entities) {
        try {
            for (int i = 0; i < entities.size(); i += BATCH_SIZE) {
                int end = Math.min(i + BATCH_SIZE, entities.size());
                enterpriseBaseInfoMapper.insertBatch(entities.subList(i, end));
            }
        } catch (DuplicateKeyException ex) {
            insertOneByOneIgnoreDuplicate(entities);
        }
    }

    private void insertOneByOneIgnoreDuplicate(List<CcdiEnterpriseBaseInfo> entities) {
        for (CcdiEnterpriseBaseInfo entity : entities) {
            if (enterpriseBaseInfoMapper.selectById(entity.getSocialCreditCode()) != null) {
                continue;
            }
            try {
                enterpriseBaseInfoMapper.insert(entity);
            } catch (DuplicateKeyException duplicate) {
                if (enterpriseBaseInfoMapper.selectById(entity.getSocialCreditCode()) == null) {
                    throw duplicate;
                }
            }
        }
    }

    private String trimToNull(String value) {
        if (StringUtils.isEmpty(value)) {
            return null;
        }
        return value.trim();
    }
}
