package cd.casic.module.execute.docker.service.impl;

import cd.casic.module.execute.docker.DockerClientFactory;
import cd.casic.module.execute.docker.service.IMonitorService;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.model.Statistics;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.*;
import java.util.function.Consumer;

/**
 * @description:
 * @author: mianbin
 * @date: 2025/5/28 11:07
 * @version: 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MonitorService implements IMonitorService {

    private final DockerClientFactory dockerClientFactory;

    /*
     * 镜像里面的监控获取，没问题，但是，如果你是获取持续的，比如一直获取，那么这个就不行，这个是一次的
     * */
    @Override
    public Statistics monitorDocker(String clientId, String containerId) {
        CompletableFuture<Statistics> future = new CompletableFuture<>();
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);

        Consumer<Statistics> onNextConsumer = future::complete;

        Consumer<Throwable> onErrorConsumer = throwable -> {
            if (throwable instanceof RuntimeException) {
                return;
            }
            log.error("docker 拉取状态异常，{}", throwable.getMessage());
            future.completeExceptionally(throwable);
        };

        dockerClient.statsCmd(containerId).exec(new ResultCallback.Adapter<Statistics>() {
            @SneakyThrows(RuntimeException.class)
            @Override
            public void onNext(Statistics statistics) {
                onNextConsumer.accept(statistics);
            }

            @Override
            public void onError(Throwable throwable) {
                onErrorConsumer.accept(throwable);
            }
        });
        try {
            // 最多等待 3 秒
            Statistics statistics = future.get(3, TimeUnit.SECONDS);
            return statistics;
        } catch (TimeoutException e) {
            log.warn("获取 Docker 统计信息超时");
            return new Statistics();
        } catch (InterruptedException | ExecutionException e) {
            log.error("获取 Docker 统计信息出错", e);
            return new Statistics();
        }
    }

    /*
     * 镜像里面的监控获取，一直获取
     * */
    @Override
    public BlockingQueue<Statistics> monitorsDocker(String clientId, String containerId) {
        // 创建一个阻塞队列用于存储持续获取的统计信息
        BlockingQueue<Statistics> statsQueue = new LinkedBlockingQueue<>();
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);

        Consumer<Statistics> onNextConsumer = statistics -> {
            try {
                statsQueue.put(statistics);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("向队列添加统计信息时被中断", e);
            }
        };

        dockerClient.statsCmd(containerId).exec(new ResultCallback.Adapter<Statistics>() {
            @Override
            public void onNext(Statistics statistics) {
                onNextConsumer.accept(statistics);
            }

            @Override
            public void onError(Throwable throwable) {
                log.error("docker 拉取状态异常，{}", throwable.getMessage());
            }
        });
        return statsQueue;
    }

    @Override
    public BlockingQueue<Statistics> monitorsDockerEnableClose(String clientId, String containerId) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        MonitorTask monitorTask = new MonitorTask(dockerClient, containerId);
        return monitorTask.getStatsQueue();
    }


    @Getter
    public static class MonitorTask {
        private final BlockingQueue<Statistics> statsQueue = new LinkedBlockingQueue<>();
        private final ResultCallback.Adapter<Statistics> callback;
        private final DockerClient dockerClient;
        private boolean isClosed = false;

        public MonitorTask(DockerClient dockerClient, String containerId) {
            this.dockerClient = dockerClient;
            this.callback = new ResultCallback.Adapter<Statistics>() {
                @Override
                public void onNext(Statistics statistics) {
                    if (!isClosed) {
                        try {
                            statsQueue.put(statistics);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            log.error("向队列添加统计信息时被中断", e.getMessage());
                        }
                    } else {
                        /*
                         * 这个显得多余，但是测试时候确实遇到callback.close()无效，然后线程一直挂起的情况
                         * 这个加个保险
                         * */
                        Thread.currentThread().interrupt();
                    }
                }
            };
            dockerClient.statsCmd(containerId).exec(callback);
        }

        public void close() {
            if (!isClosed) {
                isClosed = true;
                try {
                    callback.close();
                } catch (Exception e) {
                    log.error("关闭监控回调时出错", e);
                }
            }
        }
    }

}
