package org.hzhub.crm.task;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hzhub.common.tenant.helper.TenantHelper;
import org.hzhub.crm.domain.CrmSyncLog;
import org.hzhub.crm.service.CustomerSyncService;
import org.hzhub.crm.service.TenantCompanyService;
import org.hzhub.system.domain.SysTenant;
import org.hzhub.system.mapper.SysTenantMapper;
import org.hzhub.system.service.ISysConfigService;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * CRM-ERP客户同步定时任务（动态调度，多租户独立）
 * <p>支持运行时启动/停止/修改频率，配置存储在 sys_config 表中</p>
 * <p>每个租户独立执行，未配置ERP公司映射的租户自动跳过</p>
 *
 * @author hzhub
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CustomerSyncTask {

    private static final String CRON_CONFIG_KEY = "crm.sync.cron";
    private static final String ENABLED_CONFIG_KEY = "crm.sync.enabled";

    private final CustomerSyncService customerSyncService;
    private final TenantCompanyService tenantCompanyService;
    private final ISysConfigService configService;
    private final SysTenantMapper tenantMapper;
    private final TaskScheduler taskScheduler;

    private volatile ScheduledFuture<?> scheduledFuture;

    /**
     * 应用启动完成后，如果配置为启用则自动启动定时任务
     */
    @EventListener(ApplicationReadyEvent.class)
    public void init() {
        try {
            String enabled = configService.selectConfigByKey(ENABLED_CONFIG_KEY);
            if ("true".equals(enabled)) {
                start();
            }
        } catch (Exception e) {
            log.warn("初始化CRM同步定时任务失败: {}", e.getMessage());
        }
    }

    /**
     * 启动定时任务
     */
    public synchronized void start() {
        if (scheduledFuture != null && !scheduledFuture.isCancelled()) {
            log.info("CRM同步定时任务已在运行中");
            return;
        }

        String cron = configService.selectConfigByKey(CRON_CONFIG_KEY);
        if (cron == null || cron.isBlank()) {
            cron = "0 0 2 * * ?"; // 默认每日凌晨2点
        }

        log.info("启动CRM同步定时任务, cron: {}", cron);
        scheduledFuture = taskScheduler.schedule(() -> {
            try {
                log.info("[定时任务] 开始执行CRM-ERP客户同步（多租户）");
                syncAllTenants();
                log.info("[定时任务] CRM客户同步全部完成");
            } catch (Exception e) {
                log.error("[定时任务] CRM客户同步异常", e);
            }
        }, new CronTrigger(cron));

        configService.updateConfigByKey(ENABLED_CONFIG_KEY, "true");
    }

    /**
     * 停止定时任务
     */
    public synchronized void stop() {
        if (scheduledFuture == null) {
            log.info("CRM同步定时任务未启动");
            return;
        }

        log.info("停止CRM同步定时任务");
        scheduledFuture.cancel(false);
        scheduledFuture = null;
        configService.updateConfigByKey(ENABLED_CONFIG_KEY, "false");
    }

    /**
     * 检查是否正在运行
     */
    public boolean isRunning() {
        return scheduledFuture != null && !scheduledFuture.isCancelled();
    }

    /**
     * 获取当前 cron 表达式
     */
    public String getCurrentCron() {
        return configService.selectConfigByKey(CRON_CONFIG_KEY);
    }

    /**
     * 设置 cron 表达式
     */
    public synchronized void setCron(String cron) {
        configService.updateConfigByKey(CRON_CONFIG_KEY, cron);
        // 如果正在运行，重启以应用新 cron
        if (isRunning()) {
            stop();
            start();
        }
    }

    /**
     * 遍历所有租户，依次执行同步
     */
    private void syncAllTenants() {
        List<SysTenant> tenants = tenantMapper.selectList(
            new LambdaQueryWrapper<SysTenant>()
                .eq(SysTenant::getStatus, "0")
        );

        log.info("共发现 {} 个有效租户，开始逐个执行CRM同步", tenants.size());

        AtomicInteger successCount = new AtomicInteger(0);
        AtomicInteger skipCount = new AtomicInteger(0);
        AtomicInteger errorCount = new AtomicInteger(0);

        for (SysTenant tenant : tenants) {
            final String tenantId = tenant.getTenantId();
            try {
                TenantHelper.dynamic(tenantId, () -> {
                    // 检查租户是否配置了ERP公司映射
                    List<String> companyIds = tenantCompanyService.getTenantCompanyIds(tenantId);
                    if (companyIds.isEmpty()) {
                        log.info("租户[{}]未配置ERP公司映射，跳过同步", tenantId);
                        skipCount.incrementAndGet();
                        return;
                    }

                    log.info("租户[{}]开始CRM-ERP客户同步，关联{}家公司", tenantId, companyIds.size());
                    try {
                        CrmSyncLog syncLog = customerSyncService.executeSync("SCHEDULED", "SYSTEM");
                        log.info("租户[{}]同步完成: 扫描={}, 同步={}, 更新={}, 预警={}, 错误={}",
                            tenantId, syncLog.getTotalCount(), syncLog.getSyncedCount(),
                            syncLog.getUpdatedCount(), syncLog.getAlertCount(), syncLog.getErrorCount());
                        successCount.incrementAndGet();
                    } catch (Exception e) {
                        log.error("租户[{}]CRM同步失败: {}", tenantId, e.getMessage(), e);
                        errorCount.incrementAndGet();
                    }
                });
            } catch (Exception e) {
                log.error("切换租户[{}]上下文失败", tenantId, e);
                errorCount.incrementAndGet();
            }
        }

        log.info("[定时任务] 多租户CRM同步完成: 成功={}, 跳过={}, 失败={}", successCount.get(), skipCount.get(), errorCount.get());
    }

    /**
     * 手动触发一次同步（管理员调用）
     */
    public CrmSyncLog executeManualSync() {
        return customerSyncService.executeSync("MANUAL", "ADMIN");
    }
}