package com.gzzm.lobster.api.admin;

import com.gzzm.lobster.config.LobsterConfig;
import com.gzzm.lobster.identity.AdminGuard;
import com.gzzm.lobster.sandbox.DockerRunner;
import com.gzzm.lobster.sandbox.SandboxException;
import com.gzzm.lobster.sandbox.SandboxPoolService;
import net.cyan.arachne.HttpMethod;
import net.cyan.arachne.annotation.Service;
import net.cyan.nest.annotation.Inject;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Service
public class AdminSandboxContainerApi {

    @Inject private DockerRunner dockerRunner;
    @Inject private SandboxPoolService sandboxPoolService;

    @Service(url = "/ai/api/admin/sandbox-containers", method = HttpMethod.all)
    public Map<String, Object> overview() throws Exception {
        AdminGuard.requireAdmin();
        Map<String, Object> out = new LinkedHashMap<>();
        out.put("timestamp", new Date());
        out.put("config", config());
        Map<String, Object> pool = new LinkedHashMap<>();
        String poolError = "";
        try {
            if (sandboxPoolService != null) {
                pool = sandboxPoolService.snapshot();
            }
        } catch (Throwable t) {
            poolError = t.getMessage();
        }
        out.put("pool", pool);

        List<Map<String, Object>> containers = new ArrayList<>();
        String dockerError = "";
        String dockerStatsError = "";
        try {
            if (dockerRunner == null) {
                throw new SandboxException("sandbox.docker_unavailable", "DockerRunner unavailable");
            }
            containers = dockerRunner.listSandboxContainers();
            List<String> runningNames = new ArrayList<>();
            for (Map<String, Object> row : containers) {
                String state = String.valueOf(row.get("state"));
                String name = String.valueOf(row.get("name"));
                if ("running".equals(state) && name != null && !name.isEmpty()) {
                    runningNames.add(name);
                }
            }
            Map<String, Map<String, Object>> stats = new LinkedHashMap<>();
            try {
                stats = dockerRunner.statsByContainerName(runningNames);
            } catch (SandboxException e) {
                dockerStatsError = e.getMessage();
            }
            for (Map<String, Object> row : containers) {
                Object name = row.get("name");
                Map<String, Object> stat = name == null ? null : stats.get(String.valueOf(name));
                row.put("stats", stat == null ? new LinkedHashMap<String, Object>() : stat);
            }
        } catch (SandboxException e) {
            dockerError = e.getMessage();
        }
        enrichPoolWithDockerState(pool, containers);
        out.put("containers", containers);
        out.put("summary", summary(containers));
        out.put("poolError", poolError);
        out.put("dockerError", dockerError);
        out.put("dockerStatsError", dockerStatsError);
        return out;
    }

    @SuppressWarnings("unchecked")
    private void enrichPoolWithDockerState(Map<String, Object> pool, List<Map<String, Object>> containers) {
        if (pool == null || containers == null) return;
        Object rawSlots = pool.get("slots");
        if (!(rawSlots instanceof List)) return;
        Map<String, Map<String, Object>> byName = new LinkedHashMap<>();
        for (Map<String, Object> row : containers) {
            if (row == null || row.get("name") == null) continue;
            byName.put(String.valueOf(row.get("name")), row);
        }
        for (Object raw : (List<?>) rawSlots) {
            if (!(raw instanceof Map)) continue;
            Map<String, Object> slot = (Map<String, Object>) raw;
            Object name = slot.get("containerName");
            Map<String, Object> docker = name == null ? null : byName.get(String.valueOf(name));
            if (docker != null) {
                slot.put("dockerStatus", docker.get("state"));
                slot.put("dockerContainerId", docker.get("id"));
                slot.put("dockerStatusText", docker.get("status"));
            }
        }
    }

    private Map<String, Object> config() {
        Map<String, Object> m = new LinkedHashMap<>();
        m.put("sandboxPoolEnabled", Boolean.valueOf(LobsterConfig.isSandboxPoolEnabled()));
        m.put("sandboxPoolSize", Integer.valueOf(LobsterConfig.getSandboxPoolSize()));
        m.put("sandboxPoolRoot", LobsterConfig.getSandboxPoolRoot());
        m.put("sandboxImage", LobsterConfig.getSandboxImage());
        m.put("sandboxMemoryMb", Integer.valueOf(LobsterConfig.getSandboxMemoryMb()));
        m.put("sandboxCpus", Double.valueOf(LobsterConfig.getSandboxCpus()));
        m.put("sandboxPidsLimit", Integer.valueOf(LobsterConfig.getSandboxPidsLimit()));
        m.put("sandboxDockerBin", LobsterConfig.getSandboxDockerBin());
        return m;
    }

    private Map<String, Object> summary(List<Map<String, Object>> containers) {
        int total = 0, running = 0, created = 0, exited = 0, pool = 0, oneOff = 0;
        if (containers != null) {
            for (Map<String, Object> row : containers) {
                total++;
                if (Boolean.TRUE.equals(row.get("pool"))) pool++;
                else oneOff++;
                String state = String.valueOf(row.get("state"));
                if ("running".equals(state)) running++;
                else if ("created".equals(state)) created++;
                else if ("exited".equals(state)) exited++;
            }
        }
        Map<String, Object> m = new LinkedHashMap<>();
        m.put("total", Integer.valueOf(total));
        m.put("running", Integer.valueOf(running));
        m.put("created", Integer.valueOf(created));
        m.put("exited", Integer.valueOf(exited));
        m.put("pool", Integer.valueOf(pool));
        m.put("oneOff", Integer.valueOf(oneOff));
        return m;
    }
}
