package com.ruoyi.jarvis.service.impl;

import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.jarvis.domain.TencentDocBatchPushRecord;
import com.ruoyi.jarvis.domain.TencentDocOperationLog;
import com.ruoyi.jarvis.mapper.TencentDocBatchPushRecordMapper;
import com.ruoyi.jarvis.mapper.TencentDocOperationLogMapper;
import com.ruoyi.jarvis.service.ITencentDocBatchPushService;
import com.ruoyi.jarvis.wecom.WxSendGoofishNotifyClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 腾讯文档批量推送记录服务实现
 */
@Service
public class TencentDocBatchPushServiceImpl implements ITencentDocBatchPushService {

    private static final Logger log = LoggerFactory.getLogger(TencentDocBatchPushServiceImpl.class);

    private static final String REDIS_STALE_BATCH_NOTIFY_KEY = "tendoc:batch:stale-notified:";

    @Resource
    private TencentDocBatchPushRecordMapper batchPushRecordMapper;

    @Resource
    private TencentDocOperationLogMapper operationLogMapper;

    @Resource
    private RedisCache redisCache;

    @Resource
    private WxSendGoofishNotifyClient wxSendGoofishNotifyClient;

    /** 仍为 RUNNING 超过该分钟数则归档为 INTERRUPTED（可配置） */
    @Value("${jarvis.tencent-doc.batch-push.stale-running-threshold-minutes:45}")
    private int staleRunningThresholdMinutes;

    private static final String DELAYED_PUSH_TASK_KEY = "tendoc:delayed_push:task_scheduled";
    private static final String DELAYED_PUSH_SCHEDULE_TIME_KEY = "tendoc:delayed_push:next_time";

    @Override
    public String createBatchPushRecord(String fileId, String sheetId, String pushType,
                                         String triggerSource, Integer startRow, Integer endRow) {
        String batchId = UUID.randomUUID().toString().replace("-", "");
        
        TencentDocBatchPushRecord record = new TencentDocBatchPushRecord();
        record.setBatchId(batchId);
        record.setFileId(fileId);
        record.setSheetId(sheetId);
        record.setPushType(pushType);
        record.setTriggerSource(triggerSource);
        record.setStartTime(new Date());
        record.setStartRow(startRow);
        record.setEndRow(endRow);
        record.setTotalRows(endRow - startRow + 1);
        record.setSuccessCount(0);
        record.setSkipCount(0);
        record.setErrorCount(0);
        record.setStatus("RUNNING");
        
        batchPushRecordMapper.insertBatchPushRecord(record);
        
        return batchId;
    }

    @Override
    public void updateBatchPushRecord(String batchId, String status, Integer successCount,
                                       Integer skipCount, Integer errorCount, String resultMessage, String errorMessage) {
        TencentDocBatchPushRecord record = new TencentDocBatchPushRecord();
        record.setBatchId(batchId);
        record.setEndTime(new Date());
        record.setStatus(status);
        record.setSuccessCount(successCount);
        record.setSkipCount(skipCount);
        record.setErrorCount(errorCount);
        record.setResultMessage(resultMessage);
        record.setErrorMessage(errorMessage);
        
        // 计算耗时
        TencentDocBatchPushRecord existingRecord = batchPushRecordMapper.selectByBatchId(batchId);
        if (existingRecord != null && existingRecord.getStartTime() != null) {
            long durationMs = new Date().getTime() - existingRecord.getStartTime().getTime();
            record.setDurationMs(durationMs);
        }
        
        batchPushRecordMapper.updateBatchPushRecord(record);
    }

    @Override
    public TencentDocBatchPushRecord getBatchPushRecord(String batchId) {
        TencentDocBatchPushRecord record = batchPushRecordMapper.selectByBatchId(batchId);
        if (record != null && record.getFileId() != null && !record.getFileId().trim().isEmpty()) {
            reconcileStaleRunningRecords(record.getFileId());
            record = batchPushRecordMapper.selectByBatchId(batchId);
        }
        if (record != null) {
            // 加载关联的操作日志
            List<TencentDocOperationLog> logs = operationLogMapper.selectLogsByBatchId(batchId);
            record.setOperationLogs(logs);
        }
        return record;
    }

    @Override
    public List<TencentDocBatchPushRecord> getBatchPushRecordListWithLogs(String fileId, String sheetId, Integer limit) {
        reconcileStaleRunningRecords(fileId);

        TencentDocBatchPushRecord query = new TencentDocBatchPushRecord();
        query.setFileId(fileId);
        query.setSheetId(sheetId);
        
        List<TencentDocBatchPushRecord> records = limit != null && limit > 0 
            ? batchPushRecordMapper.selectRecentRecords(fileId, limit)
            : batchPushRecordMapper.selectBatchPushRecordList(query);
        
        // 为每条记录加载操作日志
        for (TencentDocBatchPushRecord record : records) {
            List<TencentDocOperationLog> logs = operationLogMapper.selectLogsByBatchId(record.getBatchId());
            record.setOperationLogs(logs);
        }
        
        return records;
    }

    @Override
    public TencentDocBatchPushRecord getLastSuccessRecord(String fileId, String sheetId) {
        TencentDocBatchPushRecord record = batchPushRecordMapper.selectLastSuccessRecord(fileId, sheetId);
        if (record != null) {
            List<TencentDocOperationLog> logs = operationLogMapper.selectLogsByBatchId(record.getBatchId());
            record.setOperationLogs(logs);
        }
        return record;
    }

    @Override
    public Map<String, Object> getPushStatusAndCountdown() {
        Map<String, Object> result = new HashMap<>();
        
        // 检查是否有定时任务（通过时间戳是否存在来判断）
        Long scheduleTime = redisCache.getCacheObject(DELAYED_PUSH_SCHEDULE_TIME_KEY);
        
        // 如果有推送时间戳，就认为有定时任务
        boolean isScheduled = scheduleTime != null;
        result.put("isScheduled", isScheduled);
        
        if (isScheduled && scheduleTime != null) {
            long now = System.currentTimeMillis();
            long remainingMs = scheduleTime - now;
            
            if (remainingMs > 0) {
                result.put("scheduledTime", new Date(scheduleTime));
                result.put("remainingSeconds", remainingMs / 1000);
                result.put("remainingMs", remainingMs);
                
                // 格式化倒计时显示
                long minutes = remainingMs / 60000;
                long seconds = (remainingMs % 60000) / 1000;
                result.put("countdownText", String.format("%d分%d秒", minutes, seconds));
            } else {
                result.put("remainingSeconds", 0);
                result.put("remainingMs", 0);
                result.put("countdownText", "即将执行");
            }
        } else {
            result.put("scheduledTime", null);
            result.put("remainingSeconds", 0);
            result.put("remainingMs", 0);
            result.put("countdownText", "无定时任务");
        }
        
        return result;
    }

    @Override
    public void reconcileStaleRunningRecords(String fileId) {
        if (fileId == null || fileId.trim().isEmpty() || staleRunningThresholdMinutes <= 0) {
            return;
        }
        Date before = new Date(System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(staleRunningThresholdMinutes));
        List<TencentDocBatchPushRecord> stale = batchPushRecordMapper.selectRunningRecordsBefore(fileId, before);
        if (stale == null || stale.isEmpty()) {
            return;
        }
        for (TencentDocBatchPushRecord r : stale) {
            String bid = r.getBatchId();
            if (bid == null || bid.isEmpty()) {
                continue;
            }
            TencentDocBatchPushRecord fresh = batchPushRecordMapper.selectByBatchId(bid);
            if (fresh == null || !"RUNNING".equals(fresh.getStatus())) {
                continue;
            }
            String resultMsg = String.format(
                "任务已中断：超过 %d 分钟仍处于「执行中」（可能请求超时、进程退出或服务重启），系统已自动标记为结束。批次: %s",
                staleRunningThresholdMinutes, bid);
            String errMsg = "长时间未完成，自动归档为已中断";
            try {
                updateBatchPushRecord(bid, "INTERRUPTED", 0, 0, 0, resultMsg, errMsg);
                log.warn("归档超时未结束的批量推送记录 batchId={} thresholdMinutes={}", bid, staleRunningThresholdMinutes);
            } catch (Exception e) {
                log.error("归档超时批量推送记录失败 batchId={}", bid, e);
                continue;
            }
            String dedupeKey = REDIS_STALE_BATCH_NOTIFY_KEY + bid;
            if (redisCache.getCacheObject(dedupeKey) != null) {
                continue;
            }
            String pushText = "【腾讯文档推送】批次长时间未结束，已标记为「已中断」\n" + resultMsg;
            boolean ok = wxSendGoofishNotifyClient.pushGoofishAgentText(null, "", pushText);
            if (ok) {
                redisCache.setCacheObject(dedupeKey, "1", 7, TimeUnit.DAYS);
            }
        }
    }
}

