package org.hzhub.crm.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hzhub.common.core.constant.SystemConstants;
import org.hzhub.common.core.exception.ServiceException;
import org.hzhub.common.core.utils.StringUtils;
import org.hzhub.common.mybatis.core.page.PageQuery;
import org.hzhub.common.mybatis.core.page.TableDataInfo;
import org.hzhub.common.satoken.utils.LoginHelper;
import org.hzhub.common.tenant.helper.TenantHelper;
import org.hzhub.crm.domain.CrmDealer;
import org.hzhub.crm.domain.CrmSyncAlert;
import org.hzhub.crm.domain.CrmSyncLog;
import org.hzhub.crm.domain.vo.CrmSyncAlertVo;
import org.hzhub.crm.domain.vo.CrmSyncLogVo;
import org.hzhub.crm.domain.vo.InstantSyncResult;
import org.hzhub.crm.mapper.CrmDealerMapper;
import org.hzhub.crm.mapper.CrmSyncAlertMapper;
import org.hzhub.crm.mapper.CrmSyncLogMapper;
import org.hzhub.system.domain.SysTenantCompany;
import org.hzhub.system.domain.SysUser;
import org.hzhub.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * CRM-ERP客户同步服务
 *
 * 同步流程：
 * 1. 创建同步日志
 * 2. 获取所有ERP公司ID列表（从租户-公司映射配置，不限当前租户）
 * 3. 获取ERP系统中这些公司ID下的所有客户清单
 * 4. 扫描CRM中所有绑定了customerCode的经销商（用于匹配）
 * 5. 逐个ERP客户同步：
 *    - CRM有匹配(customerCode相同) → 更新CRM字段
 *    - CRM无匹配且ERP未停用 → 新增经销商记录
 * 6. 更新同步日志完成状态
 *
 * @author hzhub
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CustomerSyncService {

    private final CrmDealerMapper dealerMapper;
    private final CrmSyncLogMapper syncLogMapper;
    private final CrmSyncAlertMapper alertMapper;
    private final ErpIntegrationService erpIntegrationService;
    private final TenantCompanyService tenantCompanyService;
    private final SysUserMapper userMapper;

    /**
     * 执行同步（定时任务或手动触发）
     *
     * @param syncType 同步类型 SCHEDULED/MANUAL
     * @param operator 操作人
     * @return 同步日志
     */
    @Transactional(rollbackFor = Exception.class)
    public CrmSyncLog executeSync(String syncType, String operator) {
        // 1. 创建同步日志
        CrmSyncLog syncLog = createSyncLog(syncType, operator);

        try {
            // 2. 获取所有ERP公司ID列表（从租户-公司映射配置，不限当前租户）
            List<SysTenantCompany> tenantCompanies = tenantCompanyService.getAllTenantCompanies();
            List<String> companyIds = tenantCompanies.stream()
                .map(SysTenantCompany::getErpCompanyId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());

            // 构建公司ID -> 租户ID的映射（用于新增经销商时确定租户归属）
            Map<String, String> companyToTenantMap = tenantCompanies.stream()
                .filter(tc -> StringUtils.isNotBlank(tc.getErpCompanyId()) && StringUtils.isNotBlank(tc.getTenantId()))
                .collect(Collectors.toMap(
                    SysTenantCompany::getErpCompanyId,
                    SysTenantCompany::getTenantId,
                    (v1, v2) -> v1  // 如果同一公司映射多个租户，取第一个
                ));

            if (companyIds.isEmpty()) {
                log.warn("未配置租户-公司映射，同步终止");
                syncLog.setStatus("COMPLETED");
                syncLog.setErrorMsg("未配置租户-公司映射");
                syncLog.setTotalCount(0);
                finishSyncLog(syncLog);
                return syncLog;
            }

            // 3. 获取ERP系统中这些公司ID下的所有客户清单
            String companyIdsParam = companyIds.stream().collect(Collectors.joining(","));
            List<Map<String, Object>> erpCustomers = erpIntegrationService.getCustomerSelectList(null, companyIdsParam);
            syncLog.setTotalCount(erpCustomers.size());
            log.info("获取ERP客户清单: companyIds={}, count={}", companyIdsParam, erpCustomers.size());

            // 4. 扫描CRM中所有绑定了customerCode的经销商（忽略租户过滤）
            Map<String, CrmDealer> crmDealerMap = TenantHelper.ignore(() -> {
                List<CrmDealer> dealers = dealerMapper.selectList(
                    new LambdaQueryWrapper<CrmDealer>()
                        .eq(CrmDealer::getDelFlag, SystemConstants.NORMAL)
                        .isNotNull(CrmDealer::getCustomerCode)
                        .ne(CrmDealer::getCustomerCode, "")
                );
                return dealers.stream()
                    .collect(Collectors.toMap(CrmDealer::getCustomerCode, d -> d, (d1, d2) -> d1));
            });

            // 5. 预加载用户昵称 -> 用户ID映射（用于匹配负责人）
            Map<String, Long> nicknameToUserIdMap = loadUserNicknameMap();

            int syncedCount = 0, updatedCount = 0, newCount = 0, alertCount = 0, errorCount = 0;

            // 6. 逐个ERP客户同步
            for (Map<String, Object> erpCustomer : erpCustomers) {
                try {
                    String customerCode = (String) erpCustomer.get("customerCode");
                    if (StringUtils.isBlank(customerCode)) {
                        continue;
                    }

                    Integer isStop = (Integer) erpCustomer.get("isStop");
                    boolean isErpStopped = isStop != null && isStop == 1;

                    CrmDealer existingDealer = crmDealerMap.get(customerCode);

                    if (existingDealer != null) {
                        // CRM已有匹配记录 -> 更新
                        SyncResult result = syncExistingDealer(existingDealer, erpCustomer, syncLog.getId());
                        syncedCount++;
                        if (result.updated) updatedCount++;
                        if (result.hasAlert) alertCount++;
                    } else if (!isErpStopped) {
                        // CRM无匹配且ERP未停用 -> 新增
                        String erpCompanyCode = (String) erpCustomer.get("companyCode");
                        String targetTenantId = companyToTenantMap.get(erpCompanyCode);

                        if (StringUtils.isBlank(targetTenantId)) {
                            log.warn("ERP客户{}的公司{}未找到租户映射，跳过新增", customerCode, erpCompanyCode);
                            continue;
                        }

                        SyncResult result = createNewDealer(erpCustomer, targetTenantId, nicknameToUserIdMap);
                        if (result.created) newCount++;
                        syncedCount++;
                    }
                } catch (Exception e) {
                    log.error("同步ERP客户失败: customerCode={}", erpCustomer.get("customerCode"), e);
                    errorCount++;
                }
            }

            // 7. 更新日志完成状态
            syncLog.setStatus("COMPLETED");
            syncLog.setSyncedCount(syncedCount);
            syncLog.setUpdatedCount(updatedCount);
            syncLog.setAlertCount(alertCount);
            syncLog.setErrorCount(errorCount);

            log.info("同步完成: total={}, synced={}, updated={}, new={}, alerts={}, errors={}",
                syncLog.getTotalCount(), syncedCount, updatedCount, newCount, alertCount, errorCount);

        } catch (Exception e) {
            log.error("同步执行失败", e);
            syncLog.setStatus("FAILED");
            syncLog.setErrorMsg(e.getMessage());
        }

        finishSyncLog(syncLog);
        return syncLog;
    }

    /**
     * 同步已存在的经销商（更新模式）
     */
    private SyncResult syncExistingDealer(CrmDealer dealer, Map<String, Object> erpCustomer, Long syncLogId) {
        SyncResult result = new SyncResult();
        boolean needsUpdate = false;

        // ERP覆盖字段同步
        // 名称
        String erpName = (String) erpCustomer.get("customerName");
        if (StringUtils.isNotBlank(erpName) && !Objects.equals(dealer.getDealerName(), erpName)) {
            dealer.setDealerName(erpName);
            needsUpdate = true;
            result.updated = true;
        }

        // 省份
        String erpProvince = (String) erpCustomer.get("province");
        if (StringUtils.isNotBlank(erpProvince) && !Objects.equals(dealer.getProvince(), erpProvince)) {
            dealer.setProvince(erpProvince);
            needsUpdate = true;
            result.updated = true;
        }

        // 城市
        String erpCity = (String) erpCustomer.get("city");
        if (StringUtils.isNotBlank(erpCity) && !Objects.equals(dealer.getCity(), erpCity)) {
            dealer.setCity(erpCity);
            needsUpdate = true;
            result.updated = true;
        }

        // 状态（ERP停用映射到CRM生命周期）
        Integer erpIsStop = (Integer) erpCustomer.get("isStop");
        String targetLifecycle = (erpIsStop != null && erpIsStop == 1) ? "churn" : "active";
        if (!Objects.equals(dealer.getLifecycle(), targetLifecycle)) {
            dealer.setLifecycle(targetLifecycle);
            needsUpdate = true;
            result.updated = true;
        }

        // CRM维护字段差异检测 -> 生成预警
        checkAndCreateAlert(dealer, erpCustomer, "contactName", "CONTACT_DIFF", syncLogId, result);
        checkAndCreateAlert(dealer, erpCustomer, "phone", "CONTACT_DIFF", syncLogId, result);

        // 执行更新（忽略租户过滤）
        if (needsUpdate) {
            dealer.setUpdateTime(new Date());
            TenantHelper.ignore(() -> dealerMapper.updateById(dealer));
        }

        return result;
    }

    /**
     * 新增经销商
     */
    private SyncResult createNewDealer(Map<String, Object> erpCustomer, String tenantId, Map<String, Long> nicknameToUserIdMap) {
        SyncResult result = new SyncResult();

        CrmDealer dealer = new CrmDealer();
        dealer.setTenantId(tenantId);
        dealer.setCustomerCode((String) erpCustomer.get("customerCode"));
        dealer.setDealerName((String) erpCustomer.get("customerName"));
        dealer.setDealerCode((String) erpCustomer.get("customerCode"));  // 暂用customerCode作为dealerCode
        dealer.setContactName((String) erpCustomer.get("contactName"));
        dealer.setMobile((String) erpCustomer.get("phone"));
        dealer.setProvince((String) erpCustomer.get("province"));
        dealer.setCity((String) erpCustomer.get("city"));
        dealer.setLifecycle("active");  // 新增默认为活跃状态（ERP未停用的才会新增）
        dealer.setDelFlag(0);  // 正常状态
        dealer.setCreateTime(new Date());

        // 匹配负责人（ERP的salesName匹配用户昵称）
        String salesName = (String) erpCustomer.get("salesPersonName");
        if (StringUtils.isNotBlank(salesName) && nicknameToUserIdMap.containsKey(salesName)) {
            dealer.setOwnerUserId(nicknameToUserIdMap.get(salesName));
        }

        // 在指定租户下插入（使用动态租户）
        TenantHelper.dynamic(tenantId, () -> dealerMapper.insert(dealer));

        result.created = true;
        log.info("新增经销商: tenantId={}, customerCode={}, dealerName={}", tenantId, dealer.getCustomerCode(), dealer.getDealerName());

        return result;
    }

    /**
     * 加载用户昵称 -> 用户ID映射
     */
    private Map<String, Long> loadUserNicknameMap() {
        return TenantHelper.ignore(() -> {
            List<SysUser> users = userMapper.selectList(
                new LambdaQueryWrapper<SysUser>()
                    .eq(SysUser::getStatus, SystemConstants.NORMAL)
                    .isNotNull(SysUser::getNickName)
            );
            return users.stream()
                .filter(u -> StringUtils.isNotBlank(u.getNickName()))
                .collect(Collectors.toMap(
                    SysUser::getNickName,
                    SysUser::getUserId,
                    (v1, v2) -> v1  // 昵称相同取第一个
                ));
        });
    }

    /**
     * 检测差异并生成预警
     */
    private void checkAndCreateAlert(CrmDealer dealer, Map<String, Object> erpCustomer,
                                     String fieldName, String alertType, Long syncLogId, SyncResult result) {
        String crmValue = getDealerFieldValue(dealer, fieldName);
        String erpValue = getErpFieldValue(erpCustomer, fieldName);

        // CRM有值且与ERP不一致时生成预警
        if (StringUtils.isNotBlank(crmValue) && !Objects.equals(crmValue, erpValue)) {
            CrmSyncAlert alert = new CrmSyncAlert();
            alert.setTenantId(dealer.getTenantId());
            alert.setSyncLogId(syncLogId);
            alert.setDealerId(dealer.getDealerId());
            alert.setCustomerCode(dealer.getCustomerCode());
            alert.setAlertType(alertType);
            alert.setCrmValue(crmValue);
            alert.setErpValue(erpValue != null ? erpValue : "");
            alert.setAlertMessage(buildAlertMessage(fieldName, crmValue, erpValue));
            alert.setStatus("PENDING");
            alert.setCreateTime(new Date());

            alertMapper.insert(alert);
            result.hasAlert = true;
        }
    }

    /**
     * 即时同步（编辑时调用）
     */
    public InstantSyncResult instantSync(Long dealerId) {
        CrmDealer dealer = TenantHelper.ignore(() -> dealerMapper.selectById(dealerId));
        if (dealer == null) {
            return new InstantSyncResult(false, "经销商不存在", false, null, null);
        }

        if (StringUtils.isBlank(dealer.getCustomerCode())) {
            return new InstantSyncResult(false, "未绑定ERP客户编码", false, null, null);
        }

        Map<String, Object> erpCustomer = erpIntegrationService.getCustomerDetail(dealer.getCustomerCode());
        if (erpCustomer == null) {
            return new InstantSyncResult(false, "ERP客户不存在: " + dealer.getCustomerCode(), false, null, null);
        }

        // 执行同步
        SyncResult result = syncExistingDealer(dealer, erpCustomer, null);

        // 获取预警列表
        List<CrmSyncAlertVo> alerts = getPendingAlerts(dealerId);

        return new InstantSyncResult(
            true,
            result.updated ? "同步成功，已更新ERP最新信息" : "数据已是最新",
            result.updated,
            alerts,
            erpCustomer
        );
    }

    /**
     * 校验ERP客户编码是否有效
     */
    public boolean validateCustomerCode(String customerCode) {
        if (StringUtils.isBlank(customerCode)) {
            return false;
        }
        Map<String, Object> customer = erpIntegrationService.getCustomerDetail(customerCode);
        return customer != null;
    }

    /**
     * 获取经销商待处理预警
     */
    public List<CrmSyncAlertVo> getPendingAlerts(Long dealerId) {
        LambdaQueryWrapper<CrmSyncAlert> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CrmSyncAlert::getDealerId, dealerId)
            .eq(CrmSyncAlert::getStatus, "PENDING")
            .orderByDesc(CrmSyncAlert::getCreateTime);

        List<CrmSyncAlert> alerts = alertMapper.selectList(wrapper);
        return alerts.stream()
            .map(a -> BeanUtil.copyProperties(a, CrmSyncAlertVo.class))
            .collect(Collectors.toList());
    }

    /**
     * 处理预警
     */
    @Transactional(rollbackFor = Exception.class)
    public void resolveAlert(Long alertId, String action, String note) {
        CrmSyncAlert alert = alertMapper.selectById(alertId);
        if (alert == null) {
            throw new ServiceException("预警不存在");
        }

        String newStatus;
        switch (action) {
            case "acknowledge":
                newStatus = "ACKNOWLEDGED";
                break;
            case "resolve":
                newStatus = "RESOLVED";
                updateDealerFromAlert(alert);
                break;
            case "ignore":
                newStatus = "IGNORED";
                break;
            default:
                throw new ServiceException("无效的处理操作");
        }

        alert.setStatus(newStatus);
        alert.setResolvedBy(LoginHelper.getUserId());
        alert.setResolvedTime(new Date());
        alert.setResolvedNote(note);

        alertMapper.updateById(alert);
    }

    /**
     * 根据预警更新经销商字段
     */
    private void updateDealerFromAlert(CrmSyncAlert alert) {
        TenantHelper.ignore(() -> {
            CrmDealer dealer = dealerMapper.selectById(alert.getDealerId());
            if (dealer == null) {
                return;
            }
            // CRM维护字段由用户手动处理，此方法仅记录更新时间
            dealer.setUpdateTime(new Date());
            dealerMapper.updateById(dealer);
        });
    }

    /**
     * 分页查询同步日志
     */
    public TableDataInfo<CrmSyncLogVo> listSyncLogs(PageQuery pageQuery) {
        LambdaQueryWrapper<CrmSyncLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(CrmSyncLog::getStartTime);

        Page<CrmSyncLogVo> page = syncLogMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 分页查询预警列表（全局）
     */
    public TableDataInfo<CrmSyncAlertVo> listAlerts(String status, PageQuery pageQuery) {
        LambdaQueryWrapper<CrmSyncAlert> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(status)) {
            wrapper.eq(CrmSyncAlert::getStatus, status);
        }
        wrapper.orderByDesc(CrmSyncAlert::getCreateTime);

        Page<CrmSyncAlertVo> page = alertMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 获取同步统计数据
     */
    public Map<String, Object> getSyncStats() {
        Map<String, Object> stats = new HashMap<>();

        // 最近一次同步
        LambdaQueryWrapper<CrmSyncLog> lastWrapper = new LambdaQueryWrapper<>();
        lastWrapper.eq(CrmSyncLog::getStatus, "COMPLETED")
            .orderByDesc(CrmSyncLog::getStartTime)
            .last("LIMIT 1");
        CrmSyncLog lastSync = syncLogMapper.selectOne(lastWrapper);

        if (lastSync != null) {
            stats.put("lastSyncTime", lastSync.getStartTime());
            stats.put("lastSyncDuration", lastSync.getDuration());
            stats.put("lastSyncCount", lastSync.getSyncedCount());
            stats.put("lastSyncUpdated", lastSync.getUpdatedCount());
            stats.put("lastSyncAlerts", lastSync.getAlertCount());
            stats.put("lastSyncErrors", lastSync.getErrorCount());
        }

        // 待处理预警数量
        Long pendingAlerts = alertMapper.selectCount(
            new LambdaQueryWrapper<CrmSyncAlert>().eq(CrmSyncAlert::getStatus, "PENDING"));
        stats.put("pendingAlerts", pendingAlerts);

        // 绑定ERP编码的经销商数量（全局统计）
        Long boundDealers = TenantHelper.ignore(() -> dealerMapper.selectCount(
            new LambdaQueryWrapper<CrmDealer>()
                .eq(CrmDealer::getDelFlag, SystemConstants.NORMAL)
                .isNotNull(CrmDealer::getCustomerCode)
                .ne(CrmDealer::getCustomerCode, "")));
        stats.put("boundDealers", boundDealers);

        return stats;
    }

    // ========== 辅助方法 ==========

    private CrmSyncLog createSyncLog(String syncType, String operator) {
        CrmSyncLog log = new CrmSyncLog();
        log.setSyncType(syncType);
        log.setSyncDirection("ERP_TO_CRM");
        log.setStatus("RUNNING");
        log.setStartTime(new Date());
        log.setOperator(operator);
        syncLogMapper.insert(log);
        return log;
    }

    private void finishSyncLog(CrmSyncLog syncLog) {
        syncLog.setEndTime(new Date());
        if (syncLog.getStartTime() != null) {
            syncLog.setDuration((int) ((syncLog.getEndTime().getTime() - syncLog.getStartTime().getTime()) / 1000));
        }
        syncLogMapper.updateById(syncLog);
    }

    private String getDealerFieldValue(CrmDealer dealer, String fieldName) {
        switch (fieldName) {
            case "contactName":
                return dealer.getContactName();
            case "phone":
                return dealer.getMobile();
            default:
                return null;
        }
    }

    private String getErpFieldValue(Map<String, Object> erpCustomer, String fieldName) {
        switch (fieldName) {
            case "contactName":
                return (String) erpCustomer.get("contactName");
            case "phone":
                return (String) erpCustomer.get("phone");
            default:
                return null;
        }
    }

    private String buildAlertMessage(String fieldName, String crmValue, String erpValue) {
        String fieldLabel;
        switch (fieldName) {
            case "contactName":
                fieldLabel = "联系人";
                break;
            case "phone":
                fieldLabel = "电话";
                break;
            default:
                fieldLabel = fieldName;
        }
        return String.format("%s与ERP不一致：CRM=%s, ERP=%s", fieldLabel,
            crmValue != null ? crmValue : "空",
            erpValue != null ? erpValue : "空");
    }

    /**
     * 同步结果内部类
     */
    private static class SyncResult {
        boolean updated = false;
        boolean created = false;
        boolean hasAlert = false;
    }
}