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

import cd.casic.framework.commons.util.json.JsonUtils;
import cd.casic.framework.security.core.util.SecurityFrameworkUtils;
import cd.casic.module.execute.docker.DockerClientFactory;
import cd.casic.module.execute.docker.callback.CommandExecCallback;
import cd.casic.module.execute.docker.dataobject.model.OperateRecord;
import cd.casic.module.execute.docker.dataobject.model.RunNewContainer;
import cd.casic.module.execute.docker.service.IContainerService;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.command.TopContainerResponse;
import com.github.dockerjava.api.model.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: TODO
 * @author: mianbin
 * @date: 2025/5/26 16:34
 * @version: 1.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ContainerService implements IContainerService {

    private final DockerClientFactory dockerClientFactory;
    private final OperateRecordService operateRecordService;

    @Override
    public List<Container> list(String clientId, boolean showAll) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        return dockerClient.listContainersCmd().withShowAll(showAll).exec();
    }

    @Override
    public CreateContainerResponse run(String clientId, RunNewContainer runNewContainer) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        HostConfig hostConfig = HostConfig.newHostConfig();
        hostConfig.withBinds(Bind.parse("/host:/container:ro"))
                .withPortBindings(PortBinding.parse("12:44")).withLinks(Link.parse(""))
                .withDns(runNewContainer.getDns()).withNetworkMode("网络名");
        final CreateContainerResponse response = dockerClient
                .createContainerCmd(runNewContainer.getImageId())
                .withAliases(runNewContainer.getAlias())
                .withHostConfig(hostConfig)
                .withEnv(runNewContainer.findEnvList())
                .withName(runNewContainer.getContainerName())
                .withHostName(runNewContainer.getHostname()).exec();
        return response;
    }

    @Override
    public void start(String clientId, String containerId) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        dockerClient.startContainerCmd(containerId).exec();
        log.info("启动容器,containerId={}", containerId);
        /*增加日志*/
        extracted(containerId, "启动容器");
    }

    private void extracted(String containerId, String type) {
        try {
            Map<String, String> param = new HashMap<>();
            param.put("containerId", containerId);
            param.put("type", type);
            OperateRecord operateRecord = OperateRecord.builder()
                    .userId(SecurityFrameworkUtils.getLoginUserId())
                    /*这个是没有必要存放的*/
                    .clientId("")
                    .content(JsonUtils.toJsonString(param))
                    .name("未知")
                    .resource(OperateRecord.OperatorResource.CONTAINER_v1).build();
            operateRecordService.add(operateRecord);
        } catch (Exception ignore) {
            //ignore exception
        }
    }

    @Override
    public void stop(String clientId, String containerId) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        dockerClient.stopContainerCmd(containerId).exec();
        log.info("停止容器,containerId={}", containerId);
        /*增加日志*/
        extracted(containerId, "停止容器");
    }

    @Override
    public void pause(String clientId, String containerId) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        dockerClient.pauseContainerCmd(containerId).exec();
        log.info("暂停容器,containerId={}", containerId);
        extracted(containerId, "暂停容器");
    }

    @Override
    public void unpause(String clientId, String containerId) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        dockerClient.unpauseContainerCmd(containerId).exec();
        log.info("继续容器,containerId={}", containerId);
        extracted(containerId, "恢复容器");
    }

    @Override
    public void remove(String clientId, String containerId) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        dockerClient.removeContainerCmd(containerId)
                /*删除默认强制删除，并且挂载内容一并删除*/
                .withForce(true)
                .withRemoveVolumes(true).exec();
        log.info("移除容器,containerId={}", containerId);
        extracted(containerId, "移除容器");
    }

    @Override
    public void rename(String clientId, String containerId, String newName) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        dockerClient.renameContainerCmd(containerId).withName(newName).exec();
        log.info("重命名容器:[{}]为[{}]", containerId, newName);
        extracted(containerId, "重命名容器");
    }

    @Override
    public TopContainerResponse top(String clientId, String containerId) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        return dockerClient.topContainerCmd(containerId).withPsArgs("aux").exec();
    }

    @Override
    public InspectContainerResponse inspect(String clientId, String containerId) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        final InspectContainerResponse response =
                dockerClient.inspectContainerCmd(containerId).withSize(Boolean.TRUE).exec();
        extracted(containerId, "Inspect容器");
        return response;
    }

    @Override
    public void logs(String clientId, String containerId, String... cmd) {
        DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
        /*创建命令*/
        String execId = dockerClient.execCreateCmd(containerId)
                .withCmd(cmd)
                .withAttachStdin(true)
                .withAttachStdout(true)
                .withAttachStderr(true)
                .withTty(true)
                .exec().getId();
        // 执行命令并记录日志
        ResultCallback<Frame> callback = new CommandExecCallback(containerId);
        /*这个是异步的方法*/
        dockerClient.execStartCmd(execId)
                .withTty(true)
                .exec(callback);
    }
}
