package com.njzscloud.supervisory.biz.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njzscloud.common.mp.support.PageParam;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.supervisory.biz.mapper.TruckLocationTrackMapper;
import com.njzscloud.supervisory.biz.pojo.entity.TruckLocationTrackEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 车辆定位数据
 */
@Slf4j
@Service
public class TruckLocationTrackService extends ServiceImpl<TruckLocationTrackMapper, TruckLocationTrackEntity> implements IService<TruckLocationTrackEntity> {

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1));
    HashMap<Long, List<TruckLocationTrackEntity>> LOCATION_CACHE = new HashMap<>();
    ReentrantLock lock = new ReentrantLock();


    public static void send(SseEmitter emitter, String eventName, TruckLocationTrackEntity data) {
        try {
            emitter.send(SseEmitter.event()
                    .id(data.getId().toString())
                    .name(eventName)
                    .data(data));
        } catch (IOException e) {
            log.error("发送定位器历史记录失败", e);
        }
    }

    public static void complete(SseEmitter emitter, String eventName) {
        try {
            emitter.send(SseEmitter.event()
                    .id(IdUtil.simpleUUID())
                    .name(eventName)
                    .data("complete"));
            emitter.complete();
        } catch (IOException e) {
            log.error("发送定位器历史记录失败", e);
        }
    }

    /**
     * 新增
     */
    public void add(TruckLocationTrackEntity truckLocationTrackEntity) {
        this.save(truckLocationTrackEntity);
    }

    /**
     * 修改
     */
    public void modify(TruckLocationTrackEntity truckLocationTrackEntity) {
        this.updateById(truckLocationTrackEntity);
    }

    /**
     * 删除
     */
    @Transactional(rollbackFor = Exception.class)
    public void del(List<Long> ids) {
        this.removeBatchByIds(ids);
    }

    /**
     * 详情
     */
    public TruckLocationTrackEntity detail(Long id) {
        return this.getById(id);
    }

    /**
     * 分页查询
     */
    public PageResult<TruckLocationTrackEntity> paging(PageParam pageParam, TruckLocationTrackEntity truckLocationTrackEntity) {
        return PageResult.of(this.page(pageParam.toPage(), Wrappers.<TruckLocationTrackEntity>query(truckLocationTrackEntity)));
    }

    /* public SseEmitter history(Long orderId, LocalDateTime startTime, LocalDateTime endTime, Integer speed) {
        SseEmitter emitter = new SseEmitter(0L);

        // 提交异步任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                // 记录上一条数据的时间，用于计算间隔
                LocalDateTime lastRecordTime = null;
                int currentPage = 1;
                // 分页查询，每次500条
                while (true) {
                    // 检查是否被取消
                    if (Thread.currentThread().isInterrupted()) {
                        log.info("任务被取消");
                        complete(emitter);
                        return;
                    }

                    Page<TruckLocationTrackEntity> page = new Page<>(currentPage, 500);
                    page.addOrder(OrderItem.asc("location_time"));

                    // 分页查询当前页数据
                    IPage<TruckLocationTrackEntity> resultPage = this.page(page, Wrappers.lambdaQuery(TruckLocationTrackEntity.class)
                            .eq(TruckLocationTrackEntity::getOrderId, orderId)
                            .between(TruckLocationTrackEntity::getLocationTime, startTime, endTime));

                    List<TruckLocationTrackEntity> records = resultPage.getRecords();
                    if (records.isEmpty()) {
                        // 没有更多数据，推送完成信息
                        complete(emitter);
                        break;
                    }

                    // 处理当前页数据，按时间间隔推送
                    for (TruckLocationTrackEntity record : records) {
                        if (Thread.currentThread().isInterrupted()) {
                            log.info("任务被取消");
                            complete(emitter);
                            return;
                        }

                        LocalDateTime currentTime = record.getLocationTime();
                        // 计算与上一条数据的时间间隔
                        if (lastRecordTime != null && currentTime != null) {
                            long interval = Duration.between(lastRecordTime, currentTime).toMillis();
                            if (interval > 0) {
                                // 按实际间隔等待
                                ThreadUtil.sleep(interval);
                            }
                        }

                        // 推送当前数据
                        send(emitter, "historyData", record);

                        // 更新上一条数据的时间
                        lastRecordTime = currentTime;
                    }

                    // 判断是否为最后一页
                    if (currentPage >= resultPage.getPages()) {
                        complete(emitter);
                        break;
                    }

                    // 继续查询下一页
                    currentPage++;
                }

                // 所有数据推送完成，关闭连接
                complete(emitter);

            } catch (Exception e) {
                // 其他异常
                emitter.completeWithError(e);
            }
        }, threadPoolExecutor);

        // 注册连接关闭回调，中断任务
        emitter.onCompletion(() -> {
            log.info("连接关闭，取消任务");
            future.cancel(true);
        });
        emitter.onTimeout(() -> {
            log.info("连接超时，取消任务");
            future.cancel(true);
        });
        emitter.onError((e) -> {
            log.info("连接错误，取消任务");
            future.cancel(true);
        });

        return emitter;
    } */
    public SseEmitter history(Long orderId, LocalDateTime startTime, LocalDateTime endTime, Integer speed) {
        SseEmitter emitter = new SseEmitter(0L);

        // 提交异步任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                int currentPage = 1;
                // 分页查询，每次500条
                while (true) {
                    // 检查是否被取消
                    if (Thread.currentThread().isInterrupted()) {
                        log.info("任务被取消");
                        complete(emitter, "historyData");
                        return;
                    }

                    Page<TruckLocationTrackEntity> page = new Page<>(currentPage, 500);
                    page.addOrder(OrderItem.asc("location_time"));

                    // 分页查询当前页数据
                    IPage<TruckLocationTrackEntity> resultPage = this.page(page, Wrappers.lambdaQuery(TruckLocationTrackEntity.class)
                            .eq(TruckLocationTrackEntity::getOrderId, orderId)
                            .ge(startTime != null, TruckLocationTrackEntity::getLocationTime, startTime)
                            .le(endTime != null, TruckLocationTrackEntity::getLocationTime, endTime));

                    List<TruckLocationTrackEntity> records = resultPage.getRecords();
                    if (records.isEmpty()) {
                        // 没有更多数据，推送完成信息
                        complete(emitter, "historyData");
                        return;
                    }

                    // 处理当前页数据，按时间间隔推送
                    for (TruckLocationTrackEntity record : records) {
                        if (Thread.currentThread().isInterrupted()) {
                            log.info("任务被取消");
                            complete(emitter, "historyData");
                            return;
                        }
                        if (!ThreadUtil.sleep(speed * 1000)) {
                            log.info("任务被取消");
                            complete(emitter, "historyData");
                            return;
                        }
                        send(emitter, "historyData", record);
                    }

                    // 判断是否为最后一页
                    if (currentPage >= resultPage.getPages()) {
                        complete(emitter, "historyData");
                        return;
                    }

                    // 继续查询下一页
                    currentPage++;
                }

            } catch (Exception e) {
                // 其他异常
                emitter.completeWithError(e);
            }
        }, threadPoolExecutor);

        // 注册连接关闭回调，中断任务
        emitter.onCompletion(() -> {
            log.info("连接关闭，取消任务");
            future.cancel(true);
        });
        emitter.onTimeout(() -> {
            log.info("连接超时，取消任务");
            future.cancel(true);
        });
        emitter.onError((e) -> {
            log.info("连接错误，取消任务");
            future.cancel(true);
        });

        return emitter;
    }

    public void cache(TruckLocationTrackEntity truckLocationTrackEntity) {
        Long orderId = truckLocationTrackEntity.getOrderId();
        lock.lock();
        try {
            List<TruckLocationTrackEntity> value = LOCATION_CACHE.computeIfAbsent(orderId, k -> new LinkedList<>());
            if (value.size() >= 10) {
                value.remove(0);
            }
            value.add(truckLocationTrackEntity);
        } finally {
            lock.unlock();
        }
    }

    public SseEmitter realtime(Long orderId) {
        SseEmitter emitter = new SseEmitter(0L);

        // 提交异步任务
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                // 记录上一条数据的时间，用于计算间隔
                LocalDateTime lastRecordTime = null;
                while (true) {
                    // 检查是否被取消
                    if (Thread.currentThread().isInterrupted()) {
                        log.info("任务被取消");
                        complete(emitter, "realtimeData");
                        return;
                    }
                    lock.lock();
                    List<TruckLocationTrackEntity> records = LOCATION_CACHE.get(orderId);
                    LOCATION_CACHE.remove(orderId);
                    lock.unlock();
                    if (CollUtil.isEmpty(records)) {
                        if (ThreadUtil.sleep(1000)) {
                            log.info("任务被取消");
                            complete(emitter, "realtimeData");
                            return;
                        }
                        continue;
                    }
                    // 处理当前页数据，按时间间隔推送
                    for (TruckLocationTrackEntity record : records) {
                        if (Thread.currentThread().isInterrupted()) {
                            log.info("任务被取消");
                            complete(emitter, "realtimeData");
                            return;
                        }

                        LocalDateTime currentTime = record.getLocationTime();
                        // 计算与上一条数据的时间间隔
                        if (lastRecordTime != null && currentTime != null) {
                            long interval = Duration.between(lastRecordTime, currentTime).toMillis();
                            if (interval > 0) {
                                // 按实际间隔等待
                                ThreadUtil.sleep(interval);
                            }
                        }

                        // 推送当前数据
                        send(emitter, "realtimeData", record);

                        // 更新上一条数据的时间
                        lastRecordTime = currentTime;
                    }
                }
            } catch (Exception e) {
                // 其他异常
                emitter.completeWithError(e);
            }
        }, threadPoolExecutor);

        // 注册连接关闭回调，中断任务
        // 注册连接关闭回调，中断任务
        emitter.onCompletion(() -> {
            log.info("连接关闭，取消任务");
            future.cancel(true);
        });
        emitter.onTimeout(() -> {
            log.info("连接超时，取消任务");
            future.cancel(true);
        });
        emitter.onError((e) -> {
            log.info("连接错误，取消任务");
            future.cancel(true);
        });


        return emitter;
    }


}
