// retoor <retoor@molodetz.nl>

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

const POLL_INTERVAL_MS = 15000;
const COUNTDOWN_INTERVAL_MS = 30000;
const TICKER_CAP = 5;

export class AppOpinionWar extends Component {
    connectedCallback() {
        this._uid = this.attr("uid");
        this._topic = this.attr("topic");
        this._lastSeq = this.intAttr("seq", 0);
        this._endsAt = this.attr("ends-at");
        this._status = this.attr("status", "active");
        this._countdown = this.querySelector("[data-war-countdown]");
        this._ticker = this.querySelector("[data-war-ticker]");
        this._victory = this.querySelector("[data-war-victory]");
        this._victoryTitle = this.querySelector("[data-war-victory-title]");
        this._actions = this.querySelector("[data-war-actions]");
        this._field = this.querySelector("[data-war-field]");
        this._subscribed = false;
        this._onSubmitBound = (event) => this._onSubmit(event);
        this.addEventListener("submit", this._onSubmitBound);
        if (this._status === "active") {
            this._subscribe();
            this._poller = new Poller(() => this._poll(), POLL_INTERVAL_MS, { immediate: false, pauseHidden: true });
            this._timer = window.setInterval(() => this._tickCountdown(), COUNTDOWN_INTERVAL_MS);
            this._tickCountdown();
        }
    }

    disconnectedCallback() {
        this._teardown();
        this.removeEventListener("submit", this._onSubmitBound);
    }

    _teardown() {
        if (this._poller) {
            this._poller.stop();
            this._poller = null;
        }
        if (this._timer) {
            window.clearInterval(this._timer);
            this._timer = null;
        }
        if (this._subscribed && window.app && window.app.pubsub) {
            window.app.pubsub.unsubscribe(this._topic, this._onFrame);
            this._subscribed = false;
        }
    }

    _subscribe() {
        const app = window.app;
        if (!this._topic || !app || !app.pubsub || typeof app.pubsub.subscribe !== "function") return;
        this._onFrame = (frame) => this._apply(frame);
        app.pubsub.subscribe(this._topic, this._onFrame);
        this._subscribed = true;
    }

    async _poll() {
        if (this._status !== "active") return;
        let payload;
        try {
            payload = await Http.getJson(`/battles/${this._uid}/events?after=${this._lastSeq}`);
        } catch (error) {
            return;
        }
        (payload.events || []).forEach((event) => this._apply(event));
        if (payload.status === "resolved" && this._status === "active") {
            this._refreshState();
        }
    }

    _apply(event) {
        if (!event || typeof event.seq !== "number") return;
        if (event.seq > 0 && event.seq <= this._lastSeq) return;
        if (event.seq > 0) this._lastSeq = event.seq;
        if (typeof event.hp_a === "number" && typeof event.hp_b === "number") {
            this._renderTotals(event.hp_a, event.hp_b);
        }
        this._prependEvent(event);
        if (event.kind === "result") {
            this._refreshState();
        }
    }

    async _refreshState() {
        let war;
        try {
            war = await Http.getJson(`/battles/${this._uid}`);
        } catch (error) {
            return;
        }
        this._renderWar(war);
    }

    async _onSubmit(event) {
        const form = event.target.closest("form[data-war-action]");
        if (!form || !this.contains(form)) return;
        event.preventDefault();
        event.stopPropagation();
        const action = form.dataset.warAction;
        const confirmText = form.dataset.warConfirm;
        if (confirmText && window.app && window.app.dialog) {
            const accepted = await window.app.dialog.confirm({ message: confirmText });
            if (!accepted) return;
        }
        const button = form.querySelector("button[type=submit]");
        if (button) button.disabled = true;
        const params = {};
        new FormData(form).forEach((value, key) => {
            params[key] = value;
        });
        try {
            const result = await Http.send(form.getAttribute("action"), params);
            const war = result && result.data ? result.data.war : null;
            if (action === "fight" && war) {
                this._renderWar(war);
                this._toast(`You dealt ${result.data.damage} HP!`);
            } else {
                window.location.reload();
            }
        } catch (error) {
            this._toast(String(error && error.message ? error.message : error));
            if (button) button.disabled = false;
        }
    }

    _toast(message) {
        if (window.app && window.app.toast && typeof window.app.toast.show === "function") {
            window.app.toast.show(message, { type: "info" });
        }
    }

    _renderTotals(hpA, hpB) {
        const total = Math.max(0, hpA) + Math.max(0, hpB);
        const pctA = total ? Math.round((Math.max(0, hpA) * 100) / total) : 50;
        const pctB = total ? 100 - pctA : 50;
        this._setText("[data-war-hp-a]", hpA.toLocaleString());
        this._setText("[data-war-hp-b]", hpB.toLocaleString());
        this._setText("[data-war-pct-a]", `${pctA}%`);
        this._setText("[data-war-pct-b]", `${pctB}%`);
        const barA = this.querySelector("[data-war-bar-a]");
        const barB = this.querySelector("[data-war-bar-b]");
        if (barA) barA.style.setProperty("--war-pct", `${pctA}%`);
        if (barB) barB.style.setProperty("--war-pct", `${pctB}%`);
        if (this._field) {
            this._field.classList.toggle("war-field-lead-a", hpA > hpB);
            this._field.classList.toggle("war-field-lead-b", hpB > hpA);
        }
    }

    _setText(selector, value) {
        const node = this.querySelector(selector);
        if (node) node.textContent = value;
    }

    _renderTicker(events) {
        if (!this._ticker || !events.length) return;
        this._ticker.textContent = "";
        events.slice(0, TICKER_CAP).forEach((event) => {
            this._ticker.appendChild(this._buildEvent(event, ""));
        });
    }

    _buildEvent(event, timeLabel) {
        const item = document.createElement("li");
        item.className = `war-event war-event-${event.kind}`;
        const dot = document.createElement("span");
        dot.className = `war-event-dot war-dot-${event.faction || "n"}`;
        dot.setAttribute("aria-hidden", "true");
        const message = document.createElement("span");
        message.className = "war-event-message";
        message.textContent = event.message;
        item.append(dot, message);
        if (timeLabel) {
            const time = document.createElement("span");
            time.className = "war-event-time";
            time.textContent = timeLabel;
            item.appendChild(time);
        }
        return item;
    }

    _prependEvent(event) {
        if (!this._ticker || !event.message) return;
        const empty = this._ticker.querySelector(".war-event-empty");
        if (empty) empty.remove();
        this._ticker.prepend(this._buildEvent(event, "just now"));
        while (this._ticker.children.length > TICKER_CAP) {
            this._ticker.removeChild(this._ticker.lastChild);
        }
    }

    _renderWar(war) {
        if (!war || !war.uid) return;
        this._renderTotals(war.hp_a, war.hp_b);
        if (typeof war.last_seq === "number" && war.last_seq > this._lastSeq) {
            this._lastSeq = war.last_seq;
            this._renderTicker(war.recent_events || []);
        }
        if (war.viewer) {
            this._setText("[data-war-mine-hp]", war.viewer.hp.toLocaleString());
            const fight = this.querySelector("[data-war-fight]");
            if (fight) {
                fight.disabled = !war.viewer.can_fight || war.status !== "active";
                fight.textContent = war.viewer.can_fight
                    ? `Fight (${war.fight_cost} coins)`
                    : "On cooldown";
            }
        }
        if (war.status === "resolved" && this._status === "active") {
            this._finishResolved(war);
        }
        if (war.ends_at) this._endsAt = war.ends_at;
    }

    _finishResolved(war) {
        this._status = "resolved";
        this._teardown();
        if (this._actions) this._actions.hidden = true;
        if (this._countdown) this._countdown.textContent = "Battle ended";
        if (this._victoryTitle) {
            this._victoryTitle.textContent =
                war.winner === "draw"
                    ? `It's a draw at ${war.hp_a.toLocaleString()} HP each`
                    : `${war.winner_label} wins the war!`;
        }
        if (this._victory) this._victory.hidden = false;
    }

    _tickCountdown() {
        if (!this._countdown || this._status !== "active") return;
        const ends = Date.parse(this._endsAt);
        if (Number.isNaN(ends)) return;
        const remaining = ends - Date.now();
        if (remaining <= 0) {
            this._countdown.textContent = "Battle ended";
            this._refreshState();
            return;
        }
        const minutes = Math.floor(remaining / 60000);
        const days = Math.floor(minutes / 1440);
        const hours = Math.floor((minutes % 1440) / 60);
        const mins = minutes % 60;
        const label = days ? `${days}d ${hours}h ${mins}m` : hours ? `${hours}h ${mins}m` : `${Math.max(mins, 1)}m`;
        this._countdown.textContent = `Battle ends in ${label}`;
    }
}

customElements.define("dp-opinion-war", AppOpinionWar);
