package com.example.iot_controlhost.utils;

import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;

import com.example.iot_controlhost.utils.log.MyLog;
import com.example.iot_controlhost.utils.log.UserLog;
import com.xuexiang.rxutil2.rxjava.impl.IRxUITask;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class PollingTask {

    private static final Map<String, PollingTask> instances = new ConcurrentHashMap<>();
    private final String instanceId;
    private ScheduledExecutorService scheduler;
    private final Map<String, ScheduledFuture<?>> taskMap = new ConcurrentHashMap<>();
    private final Map<String, Long> lastUserErrorTime = new ConcurrentHashMap<>();
    private volatile boolean stopped;

    // 私有化构造函数，确保外部不能直接实例化
    private PollingTask(String instanceId) {
        this.instanceId = instanceId;
        createNewScheduler();
    }
    // 创建新的 ScheduledExecutorService 实例
    private synchronized void createNewScheduler() {
        if (scheduler != null && !scheduler.isShutdown()) {
            scheduler.shutdownNow();
        }
        scheduler = Executors.newScheduledThreadPool(3);
        taskMap.clear();
        stopped = false;
    }

    /**
     * 获取单例实例-用户正常运行时的任务
     * @return
     */
    public static synchronized PollingTask getInstance() {
        return getInstance("MAIN");
    }

    // 获取基于ID的单例实例
    public static synchronized PollingTask getInstance(String id) {
        if (!instances.containsKey(id)) {
            instances.put(id, new PollingTask(id));
        }
        return instances.get(id);
    }
    /**
     * 启动延迟任务
     *
     * @param taskId          任务ID，用于唯一标识该任务
     * @param delaySeconds    延迟时间（以秒为单位）
     * @param task            需要执行的任务
     */
    public synchronized void startDelayedTask(String taskId, long delaySeconds, @NonNull final Runnable task) {
        stopPollingTask(taskId); // 如果已有相同ID的任务，先停止
        if (stopped) {
            MyLog.auto("调度器已停止，忽略延迟任务：控制器=" + instanceId + "，任务=" + taskId);
            return;
        }
        ensureScheduler();
        try {
            ScheduledFuture<?> future = scheduler.schedule(
                    safeRunnable(taskId, task), Math.max(0, delaySeconds), TimeUnit.SECONDS);
            taskMap.put(taskId, future); // 保存任务的ScheduledFuture
            MyLog.auto("调度任务已创建：控制器=" + instanceId + "，任务=" + taskId
                    + "，延迟=" + Math.max(0, delaySeconds) + "秒");
        } catch (RejectedExecutionException e) {
            recordTaskError(taskId, "调度延迟任务被拒绝", e);
        }
    }

    /**
     * 启动IO线程的轮询任务
     *
     * @param taskId          任务ID，用于唯一标识该任务 唯一！！ 不可重复，否则会覆盖之前的任务
     * @param intervalSeconds 轮询间隔时间（以秒为单位）
     * @param task            需要在IO线程中执行的任务
     */
    public void startPollingTaskOnIOThread(String taskId, long intervalSeconds, @NonNull final Runnable task) {
        startPollingTask(taskId, intervalSeconds, () -> {
            task.run();
        });
    }

    /**
     * 启动UI线程的轮询任务
     *
     * @param taskId          任务ID，用于唯一标识该任务
     * @param intervalSeconds 轮询间隔时间（以秒为单位）
     * @param task            需要在UI线程中执行的任务
     */
    public void startPollingTaskOnUIThread(String taskId, long intervalSeconds, @NonNull final Runnable task) {
        startPollingTask(taskId, intervalSeconds, () -> {
            // 执行UI线程任务（需要在UI线程中执行）
            new Handler(Looper.getMainLooper()).post(task);
        });
    }

    /**
     * 启动IO线程任务并在UI线程中处理结果的轮询任务
     *
     * @param taskId          任务ID，用于唯一标识该任务
     * @param intervalSeconds 轮询间隔时间（以秒为单位）
     * @param ioTask          需要在IO线程中执行的任务
     * @param uiTask          需要在UI线程中执行的任务
     * @param <T>             IO任务返回结果的类型
     */
    public <T> void startPollingTask(String taskId, long intervalSeconds, @NonNull final IRxIOTask<T> ioTask, @NonNull final IRxUITask<T> uiTask) {
        startPollingTask(taskId, intervalSeconds, () -> {
            // 执行IO线程任务
            T result = ioTask.doInIOThread();
            // 将结果传递给UI线程任务
            new Handler(Looper.getMainLooper()).post(() -> uiTask.doInUIThread(result));
        });
    }

    /**
     * 启动基础轮询任务，供内部使用
     *
     * @param taskId          任务ID，用于唯一标识该任务
     * @param intervalSeconds 轮询间隔时间（以秒为单位）
     * @param task            需要执行的任务
     */
    private synchronized void startPollingTask(String taskId, long intervalSeconds, @NonNull final Runnable task) {
        stopPollingTask(taskId); // 如果已有相同ID的任务，先停止
        if (stopped) {
            MyLog.auto("调度器已停止，忽略轮询任务：控制器=" + instanceId + "，任务=" + taskId);
            return;
        }
        ensureScheduler();
        long safeInterval = Math.max(1, intervalSeconds);
        try {
            ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(
                    safeRunnable(taskId, task), 0, safeInterval, TimeUnit.SECONDS);
            taskMap.put(taskId, future); // 保存任务的ScheduledFuture
            MyLog.auto("轮询任务已创建：控制器=" + instanceId + "，任务=" + taskId
                    + "，间隔=" + safeInterval + "秒");
        } catch (RejectedExecutionException e) {
            recordTaskError(taskId, "调度轮询任务被拒绝", e);
        }
    }

    private Runnable safeRunnable(String taskId, Runnable task) {
        return () -> {
            try {
                task.run();
            } catch (Throwable throwable) {
                recordTaskError(taskId, "任务执行异常，调度器将继续运行", throwable);
            }
        };
    }

    private void recordTaskError(String taskId, String action, Throwable throwable) {
        String detail = action + "：控制器=" + instanceId + "，任务=" + taskId
                + "，异常=" + throwable.getClass().getSimpleName() + "，原因=" + throwable.getMessage();
        MyLog.autoError(detail);
        long now = System.currentTimeMillis();
        long lastTime = lastUserErrorTime.getOrDefault(taskId, 0L);
        if (now - lastTime >= TimeUnit.MINUTES.toMillis(5)) {
            lastUserErrorTime.put(taskId, now);
            UserLog.systemError("任务调度", action + "：" + instanceId + "/" + taskId);
        }
    }

    private void ensureScheduler() {
        if (scheduler == null || scheduler.isShutdown() || scheduler.isTerminated()) {
            MyLog.auto("自动任务调度器已失效，正在重建：控制器=" + instanceId);
            createNewScheduler();
        }
    }

    public boolean isAvailable() {
        return !stopped && scheduler != null && !scheduler.isShutdown() && !scheduler.isTerminated();
    }

    public boolean hasActiveTasks() {
        if (!isAvailable()) {
            return false;
        }
        taskMap.entrySet().removeIf(entry -> entry.getValue() == null
                || entry.getValue().isCancelled() || entry.getValue().isDone());
        return !taskMap.isEmpty();
    }

    // 停止所有轮询任务
    public synchronized void stopAllPollingTasks() {
        stopped = true;
        for (String taskId : taskMap.keySet()) {
            MyLog.auto("停止调度任务：控制器=" + instanceId + "，任务=" + taskId);
        }
        if (scheduler != null && !scheduler.isShutdown()) {
//            scheduler.shutdown(); // 停止所有任务
//            try {
//                if (!scheduler.awaitTermination(3, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow(); // 超时后强制停止
//                }
//            } catch (InterruptedException e) {
//                scheduler.shutdownNow(); // 当前线程被中断时强制停止
//            }
            taskMap.clear(); // 清空任务映射
        }
        // 从实例映射中移除当前实例
        instances.remove(instanceId, this);
    }
    /**
     * 停止轮询任务
     *
     * @param taskId 任务ID
     */
    public synchronized void stopPollingTask(String taskId) {
        ScheduledFuture<?> future = taskMap.get(taskId);
        if (future != null) {
            future.cancel(true); // 取消任务，中断正在执行的任务
            taskMap.remove(taskId); // 从任务列表中移除
        }
    }

    // 定义IO任务接口
    public interface IRxIOTask<T> {
        T doInIOThread();
    }

    // 定义UI任务接口
    public interface IRxUITask<T> {
        void doInUIThread(T t);
    }
}
