// retoor <retoor@molodetz.nl>

import { Http } from "./Http.js";
import { Poller } from "./Poller.js";
import { escapeHtml, wireSearch, wireBootToggle } from "./ContainerFormControls.js";

export class ContainerList {
    constructor(root) {
        this.root = root;
        this.endpoint = root.dataset.endpoint;
        this.body = document.getElementById("cm-admin-rows");
        this.pollMs = 4000;
        this.instances = [];
    }

    init() {
        this.bindActions();
        this.bindCreate();
        this.poller = new Poller(() => this.refresh(), 20000, {
            immediate: false,
            pauseHidden: true,
        });
        const pubsub = window.app && window.app.pubsub;
        if (pubsub) {
            pubsub.subscribe("container.list", (data) => {
                if (data.partial) this.merge(data.instances || []);
                else this.render(data.instances || []);
            });
        }
    }

    merge(updates) {
        const byUid = new Map(this.instances.map((inst) => [inst.uid, inst]));
        for (const update of updates) {
            const current = byUid.get(update.uid);
            byUid.set(update.uid, current ? { ...update, can_manage: current.can_manage } : update);
        }
        this.render([...byUid.values()]);
    }

    toast(message, type) {
        if (window.app && window.app.toast) window.app.toast.show(message, { type: type || "info" });
    }

    escape(value) {
        return escapeHtml(value);
    }

    bindActions() {
        if (!this.body) return;
        this.body.addEventListener("click", (e) => {
            const btn = e.target.closest("[data-cm-action]");
            if (!btn) return;
            e.preventDefault();
            const row = btn.closest(".cm-row");
            if (!row) return;
            this.runAction(btn.dataset.cmAction, row.dataset.uid, row.dataset.slug, row.dataset.name);
        });
    }

    async runAction(action, uid, slug, name) {
        if (action === "terminal") {
            if (window.app && window.app.containerTerminals && slug) {
                window.app.containerTerminals.open(slug, uid, name);
            } else {
                this.toast("Terminal needs a project slug", "error");
            }
            return;
        }
        if (action === "delete") {
            const ok = window.app && window.app.dialog
                ? await window.app.dialog.confirm(`Delete container instance "${name}"? This cannot be undone.`)
                : window.confirm(`Delete container instance "${name}"?`);
            if (!ok) return;
        }
        try {
            await Http.send(`/admin/containers/${uid}/${action}`, {});
            this.toast(`Instance ${action} requested`, "success");
            await this.refresh();
        } catch (err) {
            return;
        }
    }

    bindCreate() {
        this.form = document.getElementById("cm-admin-create-form");
        if (!this.form) return;
        wireSearch(this.form, "project", "/admin/containers/projects/search", "project_slug", (r) => r.slug, (r) => r.title);
        wireSearch(this.form, "user", "/admin/containers/users/search", "run_as_uid", (r) => r.uid, (r) => r.username);
        wireBootToggle(this.form);
        this.form.addEventListener("submit", (e) => { e.preventDefault(); this.create(); });
    }

    async create() {
        const f = this.form;
        const slug = f.elements.project_slug.value.trim();
        if (!slug) { this.toast("Pick a project first", "error"); return; }
        const params = {
            project_slug: slug,
            name: f.elements.name.value.trim(),
            run_as_uid: f.elements.run_as_uid.value.trim(),
            boot_language: f.elements.boot_language.value,
            boot_script: f.elements.boot_script.value,
            boot_command: f.elements.boot_command.value.trim(),
            restart_policy: f.elements.restart_policy.value,
            ports: f.elements.ports.value.trim(),
            env: f.elements.env.value,
            cpu_limit: f.elements.cpu_limit.value.trim(),
            mem_limit: f.elements.mem_limit.value.trim(),
            ingress_slug: f.elements.ingress_slug.value.trim(),
            ingress_port: f.elements.ingress_port.value.trim(),
            start_on_boot: f.elements.start_on_boot.checked ? "true" : "false",
            autostart: f.elements.autostart.checked ? "true" : "false",
        };
        try {
            await Http.send("/admin/containers/create", params);
            const modal = document.getElementById("cm-admin-create-modal");
            if (modal) modal.classList.remove("visible");
            f.reset();
            wireBootToggle(this.form);
            this.toast("Instance created", "success");
            await this.refresh();
        } catch (err) {
            return;
        }
    }

    async refresh() {
        this.render((await Http.getJson(this.endpoint)).instances || []);
    }

    render(instances) {
        this.instances = instances;
        if (!this.body) return;
        if (!instances.length) {
            this.body.innerHTML = `<tr><td colspan="8" class="admin-empty">No container instances yet. Create one above or open a project's container manager.</td></tr>`;
            return;
        }
        this.body.innerHTML = instances.map((inst) => this.row(inst)).join("");
    }

    row(inst) {
        const uid = this.escape(inst.uid);
        const slug = this.escape(inst.project_slug || "");
        const name = this.escape(inst.name);
        const project = inst.project_slug
            ? `<a class="cm-row-project" href="/projects/${slug}/containers">${this.escape(inst.project_title || inst.project_slug)}</a>`
            : `<span class="cm-muted">-</span>`;
        const ingress = inst.ingress_slug
            ? `<a href="/p/${this.escape(inst.ingress_slug)}" target="_blank" rel="noopener">/p/${this.escape(inst.ingress_slug)}</a>`
            : `<span class="cm-muted">-</span>`;
        const boot = inst.start_on_boot
            ? `<span class="cm-badge cm-running">on</span>`
            : `<span class="cm-muted">off</span>`;
        const actions = inst.can_manage === false
            ? `<span class="cm-muted">view only</span>`
            : `<button class="admin-btn admin-btn-sm" data-cm-action="start">Start</button>
                <button class="admin-btn admin-btn-sm" data-cm-action="stop">Stop</button>
                <button class="admin-btn admin-btn-sm" data-cm-action="restart">Restart</button>
                <button class="admin-btn admin-btn-sm" data-cm-action="terminal">Terminal</button>
                <a class="admin-btn admin-btn-sm" href="/admin/containers/${uid}/edit">Edit</a>
                <button class="admin-btn admin-btn-sm admin-btn-danger" data-cm-action="delete">Delete</button>`;
        return `<tr class="cm-row" data-uid="${uid}" data-slug="${slug}" data-name="${name}">
            <td><a class="cm-row-name" href="/admin/containers/${uid}">${name}</a></td>
            <td>${project}</td>
            <td><span class="cm-badge cm-${this.escape(inst.status)}">${this.escape(inst.status)}</span></td>
            <td>${this.escape(inst.boot_language || "none")}</td>
            <td>${ingress}</td>
            <td>${this.escape(inst.restart_policy || "never")}</td>
            <td>${boot}</td>
            <td class="cm-actions">${actions}</td>
        </tr>`;
    }
}
