// retoor <retoor@molodetz.nl>

import { Http } from "./Http.js";
import { Poller } from "./Poller.js";

export class BotMonitor {
    constructor(root) {
        this.root = root;
        this.endpoint = root.dataset.endpoint;
        this.count = document.getElementById("bots-count");
        this.pollMs = 2000;
    }

    init() {
        this.poller = new Poller(() => this.refresh(), 15000, {
            immediate: false,
            pauseHidden: true,
        });
        this.ticker = new Poller(() => this.tickAges(), 1000, {
            immediate: true,
            pauseHidden: true,
        });
        const pubsub = window.app && window.app.pubsub;
        if (pubsub) {
            pubsub.subscribe("fleet.bots", (payload) => this.apply(payload));
        }
    }

    escape(value) {
        const span = document.createElement("span");
        span.textContent = value == null ? "" : String(value);
        return span.innerHTML;
    }

    ageLabel(seconds) {
        const sec = Math.max(0, Math.floor(Number(seconds) || 0));
        if (sec < 60) return `${sec}s`;
        const minutes = Math.floor(sec / 60);
        if (minutes < 60) return `${minutes}m`;
        const hours = Math.floor(minutes / 60);
        const rest = minutes % 60;
        return rest ? `${hours}h${rest}m` : `${hours}h`;
    }

    tickAges() {
        const now = Date.now();
        for (const badge of this.root.querySelectorAll("[data-bot-age]")) {
            let capturedMs = Number(badge.dataset.capturedMs);
            if (!capturedMs) {
                const ageSeconds = Number(badge.dataset.ageSeconds) || 0;
                capturedMs = now - ageSeconds * 1000;
                badge.dataset.capturedMs = String(capturedMs);
            }
            badge.textContent = this.ageLabel((now - capturedMs) / 1000);
        }
    }

    shotMarkup(frame) {
        if (!frame.has_image) {
            return `<div class="bot-shot-empty">no frame yet</div>`;
        }
        const label = this.escape(frame.label || `bot${frame.slot}`);
        const capturedMs = Date.now() - (Number(frame.age_seconds) || 0) * 1000;
        return `<img src="${this.escape(frame.frame_url)}" alt="${label} screenshot" loading="lazy" data-lightbox>`
            + `<span class="bot-shot-age" data-bot-age data-captured-ms="${capturedMs}">${this.escape(this.ageLabel(frame.age_seconds))}</span>`;
    }

    async refresh() {
        this.apply(await Http.getJson(this.endpoint));
    }

    apply(payload) {
        const frames = (payload && payload.frames) || [];
        if (this.count) {
            this.count.textContent = `${frames.length} bots`;
        }
        if (!frames.length) {
            this.root.innerHTML = `<p class="admin-empty">No bots running. Launch the fleet on <a href="/admin/services">Services</a>.</p>`;
            return;
        }
        this.reconcile(frames);
    }

    reconcile(frames) {
        const seen = new Set();
        let previous = null;
        for (const frame of frames) {
            const slot = String(frame.slot);
            seen.add(slot);
            let card = this.root.querySelector(`.bot-card[data-slot="${this.escape(slot)}"]`);
            if (card) {
                this.update(card, frame);
            } else {
                card = document.createElement("div");
                card.innerHTML = this.card(frame);
                card = card.firstElementChild;
            }
            const anchor = previous ? previous.nextElementSibling : this.root.firstElementChild;
            if (anchor !== card) {
                this.root.insertBefore(card, anchor);
            }
            previous = card;
        }
        for (const card of [...this.root.querySelectorAll(".bot-card")]) {
            if (!seen.has(card.dataset.slot)) {
                card.remove();
            }
        }
    }

    update(card, frame) {
        const active = frame.active ? "bot-active" : "bot-idle";
        card.className = `bot-card ${active}`;
        const shot = card.querySelector(".bot-shot");
        const image = shot.querySelector("img");
        if (frame.has_image && image) {
            if (image.getAttribute("src") !== frame.frame_url) {
                image.src = frame.frame_url;
            }
            const badge = shot.querySelector("[data-bot-age]");
            if (badge) {
                badge.dataset.capturedMs = String(Date.now() - (Number(frame.age_seconds) || 0) * 1000);
                badge.textContent = this.ageLabel(frame.age_seconds);
            }
        } else if (frame.has_image || !shot.querySelector(".bot-shot-empty")) {
            shot.innerHTML = this.shotMarkup(frame);
        }
        card.querySelector(".bot-name").textContent = frame.label || `bot${frame.slot}`;
        card.querySelector(".bot-persona").textContent = frame.persona || "-";
        card.querySelector(".bot-action").textContent = frame.action || frame.status || "idle";
    }

    card(frame) {
        const slot = this.escape(frame.slot);
        const label = this.escape(frame.label || `bot${frame.slot}`);
        const persona = this.escape(frame.persona || "-");
        const action = this.escape(frame.action || frame.status || "idle");
        const active = frame.active ? "bot-active" : "bot-idle";
        return `<figure class="bot-card ${active}" data-slot="${slot}">
            <div class="bot-shot">${this.shotMarkup(frame)}</div>
            <figcaption class="bot-meta">
                <span class="bot-name">${label}</span>
                <span class="bot-persona">${persona}</span>
                <span class="bot-action">${action}</span>
            </figcaption>
        </figure>`;
    }
}
