import { ConnectionTargetResolver } from "../../connections/services/ConnectionTargetResolver.js";
import { RegionChronicleIndex } from "../services/RegionChronicleIndex.js";
import { RegionChronicleService } from "../services/RegionChronicleService.js";
import { RegionChronicleViewModel } from "../services/RegionChronicleViewModel.js";

export class EntityChroniclePanel {
    #entityId = "";
    #filters = { type: "" };
    #host = null;
    #changedHook = null;
    #entityHook = null;

    constructor({ entityId = "" } = {}) {
        this.#entityId = String(entityId || "");
    }

    setEntityId(entityId) {
        const next = String(entityId || "");
        if (next === this.#entityId) return;
        this.#entityId = next;
        this.#filters = { type: "" };
    }

    hasEvents() {
        return RegionChronicleIndex.hasEvents(this.#entityId);
    }

    getContext() {
        const records = RegionChronicleIndex.getEvents(this.#entityId);
        const allEvents = records.map(record => ({
            ...RegionChronicleViewModel.prepareEvent(record.event, { excludeEntityId: this.#entityId }),
            chronicleEntryId: record.entryId,
            regionId: record.sceneId || record.entryId,
            sceneId: record.sceneId,
            sceneName: record.sceneName
        }));
        const regions = new Map();
        for (const record of records) {
            const value = String(record.sceneId || record.entryId || "");
            if (value && !regions.has(value)) regions.set(value, String(record.sceneName || "Unnamed Region"));
        }
        const filtered = allEvents.filter(event => RegionChronicleViewModel.matchesFilters(event, this.#filters));
        const grouped = new Map();
        for (const event of filtered) {
            const key = String(event.regionId || event.chronicleEntryId || "unknown");
            if (!grouped.has(key)) {
                grouped.set(key, {
                    id: key,
                    sceneId: event.sceneId,
                    sceneName: event.sceneName || "Unnamed Region",
                    events: []
                });
            }
            grouped.get(key).events.push(event);
        }
        const regionGroups = [...grouped.values()]
            .sort((left, right) => left.sceneName.localeCompare(right.sceneName))
            .map(group => ({
                ...group,
                years: RegionChronicleViewModel.groupByYear(group.events)
            }));
        const multipleRegions = regions.size > 1;
        return {
            hasEvents: allEvents.length > 0,
            hasVisibleEvents: filtered.length > 0,
            totalEvents: allEvents.length,
            visibleEvents: filtered.length,
            filters: foundry.utils.deepClone(this.#filters),
            typeOptions: RegionChronicleViewModel.typeOptions(allEvents),
            multipleRegions,
            singleRegion: multipleRegions ? null : regionGroups[0] || null,
            regions: regionGroups,
            hasFilters: Object.values(this.#filters).some(Boolean)
        };
    }

    async render() {
        const context = this.getContext();
        for (const region of context.regions) {
            region.timelineHtml = await foundry.applications.handlebars.renderTemplate(
                "modules/augur-nexus/templates/region-population/chronicle-event-list.hbs",
                { years: region.years, compact: true }
            );
        }
        context.singleTimelineHtml = context.singleRegion
            ? await foundry.applications.handlebars.renderTemplate(
                "modules/augur-nexus/templates/region-population/chronicle-event-list.hbs",
                { years: context.singleRegion.years, compact: true }
            )
            : "";
        context.emptyTimelineHtml = context.hasVisibleEvents
            ? ""
            : await foundry.applications.handlebars.renderTemplate(
                "modules/augur-nexus/templates/region-population/chronicle-event-list.hbs",
                { years: [], compact: true }
            );
        return foundry.applications.handlebars.renderTemplate(
            "modules/augur-nexus/templates/region-population/entity-chronicle-panel.hbs",
            context
        );
    }

    activateListeners(root, hostApplication) {
        this.#watch(hostApplication);
        const panel = root?.querySelector?.("[data-entity-chronicle-panel]");
        if (!panel) return;
        for (const input of panel.querySelectorAll("[data-entity-chronicle-filter]")) {
            input.addEventListener("change", () => this.#applyFilter(input, hostApplication));
        }
        panel.querySelector("[data-action='clearEntityChronicleFilters']")?.addEventListener("click", event => {
            event.preventDefault();
            this.#filters = { type: "" };
            hostApplication.render({ parts: ["content"] });
        });
        panel.querySelectorAll("[data-action='openChronicleParticipant']").forEach(button => {
            button.addEventListener("click", async event => {
                event.preventDefault();
                const entityId = String(event.currentTarget.dataset.entityId || "");
                if (!entityId) return;
                await ConnectionTargetResolver.openNode(ConnectionTargetResolver.fromEntityReference({ entityId }));
            });
        });
        panel.querySelectorAll("[data-action='openFullChronicle']").forEach(button => {
            button.addEventListener("click", async event => {
                event.preventDefault();
                const scene = game.scenes.get(String(event.currentTarget.dataset.sceneId || ""));
                if (!scene || !await RegionChronicleService.open(scene)) ui.notifications.warn("That regional chronicle could not be found.");
            });
        });
    }

    destroy() {
        if (this.#changedHook) Hooks.off("augurNexusRegionChronicleChanged", this.#changedHook);
        if (this.#entityHook) Hooks.off("augurNexusCampaignEntitiesChanged", this.#entityHook);
        this.#changedHook = null;
        this.#entityHook = null;
        this.#host = null;
    }

    #watch(hostApplication) {
        if (!hostApplication || this.#host === hostApplication) return;
        this.destroy();
        this.#host = hostApplication;
        this.#changedHook = () => hostApplication.render({ parts: ["content"] });
        this.#entityHook = payload => {
            const reason = String(payload?.reason || "");
            const changedEntityId = String(payload?.entity?.id || "");
            if (!["updateNpc", "updateFaction", "updateLocation", "updateShip"].includes(reason) || !changedEntityId) return;
            if (changedEntityId === this.#entityId) return;
            const appearsInTimeline = RegionChronicleIndex.getEvents(this.#entityId).some(record =>
                (record.event?.participants || []).some(participant =>
                    String(participant?.id || participant?.entityId || "") === changedEntityId
                )
            );
            if (appearsInTimeline) hostApplication.render({ parts: ["content"] });
        };
        Hooks.on("augurNexusRegionChronicleChanged", this.#changedHook);
        Hooks.on("augurNexusCampaignEntitiesChanged", this.#entityHook);
    }

    #applyFilter(input, hostApplication) {
        const key = String(input.dataset.entityChronicleFilter || "");
        if (!Object.hasOwn(this.#filters, key)) return;
        this.#filters[key] = String(input.value || "").trim();
        hostApplication.render({ parts: ["content"] });
    }
}
