package com.common.service;


import com.common.entity.*;
import com.common.mapper.DeviceCollectTaskMapper;
import com.common.mapper.DeviceReceiveLogMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.time.ZoneOffset;
@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceCollectTaskUpdateService {

    private final DeviceReceiveLogMapper deviceReceiveLogMapper;
    private final DeviceCollectTaskMapper deviceCollectTaskMapper;
    private final TransactionTemplate transactionTemplate;

    /**
     * 主处理方法：更新所有设备任务的时间信息
     */
    public void updateAllDeviceTaskTimes() {
        log.info("开始更新设备采集任务时间，当前时间: {}", LocalDateTime.now());

        // 1. 查询所有设备任务
        List<DeviceCollectTask> allTasks = deviceCollectTaskMapper.selectAllTasks();
        if (CollectionUtils.isEmpty(allTasks)) {
            log.info("没有找到设备采集任务");
            return;
        }

        // 2. 查询设备接收日志的时间信息
        Map<String, DeviceCollectTaskTime> successTimes = getDeviceSuccessTimes();
        Map<String, DeviceCollectTaskTime> failTimes = getDeviceFailTimes();

        // 3. 更新任务时间
        LocalDateTime updateTime = LocalDateTime.now();
        int updatedCount = 0;

        for (DeviceCollectTask task : allTasks) {
            String deviceCollectId = task.getId().toString();

            // 获取成功时间
            DeviceCollectTaskTime successTime = successTimes.get(deviceCollectId);
            DeviceCollectTaskTime failTime = failTimes.get(deviceCollectId);

            // 准备更新时间
            LocalDateTime firstTime = task.getFirstTime().toLocalDateTime();
            LocalDateTime lastSuccessTime = null;
            LocalDateTime lastFailTime = null;

            // 设置最后成功时间
            if (successTime != null && successTime.getLastSuccessTime() != null) {
                lastSuccessTime = successTime.getLastSuccessTime();

                // 如果first_time为空，且这是首次成功，则设置first_time
                if (firstTime == null && successTime.getFirstTime() != null) {
                    firstTime = successTime.getFirstTime();
                }
            }

            // 设置最后失败时间
            if (failTime != null && failTime.getLastFailTime() != null) {
                lastFailTime = failTime.getLastFailTime();
            }

            // 如果有更新，则执行更新
            if (lastSuccessTime != null || lastFailTime != null) {
                int result = deviceCollectTaskMapper.updateTaskTime(
                        deviceCollectId,
                        firstTime,
                        lastSuccessTime,
                        lastFailTime,
                        updateTime
                );

                if (result > 0) {
                    updatedCount++;
                    log.debug("更新设备任务时间成功，设备ID: {}, 首次时间: {}, 最后成功: {}, 最后失败: {}",
                            deviceCollectId, firstTime, lastSuccessTime, lastFailTime);
                }
            }
        }

        log.info("设备采集任务时间更新完成，总计: {}，已更新: {}", allTasks.size(), updatedCount);
    }

    /**
     * 批量更新版本（性能更好）
     * 注意：不使用 @Transactional 避免长时间持锁，读操作无需事务，
     * 仅批写通过 TransactionTemplate 精确控制事务范围
     */
    public void batchUpdateDeviceTaskTimes() {
        log.info("开始批量更新设备采集任务时间，当前时间: {}", LocalDateTime.now());

        // 1. 查询所有设备任务（只读，无需事务）
        List<DeviceCollectTask> allTasks = deviceCollectTaskMapper.selectAllTasks();
        if (CollectionUtils.isEmpty(allTasks)) {
            return;
        }

        // 2. 查询时间信息（只读，无需事务）
        Map<String, DeviceCollectTaskTime> successTimes = getDeviceSuccessTimes();
        Map<String, DeviceCollectTaskTime> failTimes = getDeviceFailTimes();

        // 3. 内存中组装更新数据
        LocalDateTime updateTime = LocalDateTime.now();

        for (DeviceCollectTask task : allTasks) {
            // 获取成功和失败时间
            DeviceCollectTaskTime successTime = successTimes.get(task.getId().toString());
            DeviceCollectTaskTime failTime = failTimes.get(task.getId().toString());

            // 更新成功时间
            if (successTime != null) {
                // 如果first_time为空，则设置首次成功时间
                if (task.getFirstTime() == null && successTime.getFirstTime() != null) {
                    task.setFirstTime(successTime.getFirstTime().atOffset(ZoneOffset.UTC));
                }

                // 设置最后成功时间
                if (successTime.getLastSuccessTime() != null) {
                    task.setLastSuccessTime(successTime.getLastSuccessTime().atOffset(ZoneOffset.UTC));
                }
            }

            // 更新失败时间
            if (failTime != null && failTime.getLastFailTime() != null) {
                task.setLastFailedTime(failTime.getLastFailTime().atOffset(ZoneOffset.UTC));
            }

            task.setUpdatedAt(updateTime.atOffset(ZoneOffset.UTC));
        }

        // 4. 批量更新到数据库（仅写操作加事务，用完即释放连接）
        int updatedCount = transactionTemplate.execute(status ->
                deviceCollectTaskMapper.batchUpdateTimes(allTasks));
        log.info("批量更新完成，总计: {}，已更新: {}", allTasks.size(), updatedCount);
    }

    /**
     * 获取设备的成功时间信息
     * 优化：first_time 为恒定值，只对 first_time IS NULL 的新任务查询首次成功时间，
     * 避免对 device_receive_log进行全表扫描
     */
    private Map<String, DeviceCollectTaskTime> getDeviceSuccessTimes() {
        // 1. 查询当天的最新成功时间
        List<DeviceCollectTaskTime> dailySuccess = deviceReceiveLogMapper.selectDailySuccessTimes();

        // 2. 仅查询 first_time 为空的任务 ID，避免全表扫描
        List<Integer> tasksWithoutFirstTime = deviceCollectTaskMapper.selectTasksWithoutFirstTime();
        List<DeviceCollectTaskTime> firstSuccess;
        if (!CollectionUtils.isEmpty(tasksWithoutFirstTime)) {
            log.info("发现 {} 个任务尚未设置首次成功时间，进行精确查询", tasksWithoutFirstTime.size());
            firstSuccess = deviceReceiveLogMapper.selectFirstSuccessTimesByIds(tasksWithoutFirstTime);
        } else {
            firstSuccess = Collections.emptyList();
        }

        // 3. 合并结果
        Map<String, DeviceCollectTaskTime> result = new HashMap<>();

        // 处理首次成功时间
        for (DeviceCollectTaskTime first : firstSuccess) {
            DeviceCollectTaskTime time = new DeviceCollectTaskTime();
            time.setDeviceCollectId(first.getDeviceCollectId());
            time.setFirstTime(first.getFirstTime());
            result.put(first.getDeviceCollectId(), time);
        }

        // 处理当天成功时间
        for (DeviceCollectTaskTime daily : dailySuccess) {
            String deviceId = daily.getDeviceCollectId();
            DeviceCollectTaskTime time = result.getOrDefault(deviceId, new DeviceCollectTaskTime());
            time.setDeviceCollectId(deviceId);
            time.setLastSuccessTime(daily.getLastSuccessTime());
            result.put(deviceId, time);
        }

        return result;
    }

    /**
     * 获取设备的失败时间信息
     */
    private Map<String, DeviceCollectTaskTime> getDeviceFailTimes() {
        List<DeviceCollectTaskTime> failTimes = deviceReceiveLogMapper.selectDailyFailTimes();
        return failTimes.stream()
                .collect(Collectors.toMap(
                        DeviceCollectTaskTime::getDeviceCollectId,
                        ft -> ft,
                        (existing, replacement) -> {
                            // 如果存在重复，取更晚的时间
                            if (existing.getLastFailTime() != null &&
                                    replacement.getLastFailTime() != null &&
                                    replacement.getLastFailTime().isAfter(existing.getLastFailTime())) {
                                return replacement;
                            }
                            return existing;
                        }
                ));
    }

    /**
     * 增量更新：只处理最近一段时间的数据
     */
    public void incrementalUpdate(int hours) {
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime startTime = endTime.minusHours(hours);

        log.info("开始增量更新设备采集任务时间，时间范围: {} 到 {}", startTime, endTime);

        // 查询指定时间范围内的成功记录
        List<DeviceCollectTaskTime> successTimes = deviceReceiveLogMapper.selectSuccessTimesByRange(startTime, endTime);

        if (CollectionUtils.isEmpty(successTimes)) {
            log.info("没有找到增量数据");
            return;
        }

        LocalDateTime updateTime = LocalDateTime.now();
        int updatedCount = 0;

        for (DeviceCollectTaskTime successTime : successTimes) {
            // 查询现有任务
            DeviceCollectTask task = deviceCollectTaskMapper.selectOne(
                    new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<DeviceCollectTask>()
                            .eq("id", successTime.getDeviceCollectId())
            );

            if (task != null) {
                // 更新任务时间
                int result = deviceCollectTaskMapper.updateTaskTime(
                        successTime.getDeviceCollectId(),
                        task.getFirstTime() == null ? successTime.getFirstTime() : null,
                        successTime.getLastSuccessTime(),
                        null,  // 失败时间需要单独查询
                        updateTime
                );

                if (result > 0) {
                    updatedCount++;
                }
            }
        }

        log.info("增量更新完成，处理记录: {}，更新任务: {}", successTimes.size(), updatedCount);
    }
}