import { canRerollLocationCurrentThread, deleteLocation, rerollLocationCurrentThread } from "../../../api/locations.js";
import { openActionMenu } from "../../../api/ui.js";
import { openShopCreator } from "../../../api/shops.js";
import { ConnectionsBoard } from "../../connections/components/ConnectionsBoard.js";
import { ConnectionTargetResolver } from "../../connections/services/ConnectionTargetResolver.js";
import { OwnershipService } from "../../connections/services/OwnershipService.js";
import { ConnectionResourceFlowService } from "../../connections/services/ConnectionResourceFlowService.js";
import { TradingCenterService } from "../../connections/services/TradingCenterService.js";
import { LocationLeadershipService } from "../../connections/services/LocationLeadershipService.js";
import { PlayerNpcVisibilityDialog } from "../../nexus/applications/PlayerNpcVisibilityDialog.js";
import { PlayerLocationDisclosureDialog } from "../../nexus/applications/PlayerLocationDisclosureDialog.js";
import { PlayerVisibilityInfoPanel } from "../../nexus/applications/PlayerVisibilityInfoPanel.js";
import { DossierTabPreference } from "../../nexus/services/DossierTabPreference.js";
import { SiteCoverPicker } from "../../site/applications/SiteCoverPicker.js";
import { LocationEntityModel } from "../models/LocationEntityModel.js";
import { FactionEntityModel } from "../models/FactionEntityModel.js";
import { LocationProfileViewModel } from "../models/LocationProfileViewModel.js";
import { LocationDataEditor } from "../applications/LocationDataEditor.js";
import { CampaignEntityDossierRefresh } from "./CampaignEntityDossierRefresh.js";
import { CampaignEntityVisibilityManager } from "./CampaignEntityVisibilityManager.js";
import { CampaignEntityDisclosureManager } from "./CampaignEntityDisclosureManager.js";
import { LocationEntityStore } from "./LocationEntityStore.js";
import { LocationSceneWorkflow } from "./LocationSceneWorkflow.js";
import { LocationActionRegistry } from "./LocationActionRegistry.js";
import { CampaignEntityJournalStore } from "./CampaignEntityJournalStore.js";
import { EntityChroniclePanel } from "../../region-population/components/EntityChroniclePanel.js";

export class LocationDossierPanelController {
    #locationId = "";
    #activeTab = "profile";
    #renderProfileExtension = null;
    #showProfileTab = true;
    #connectionsBoard = null;
    #host = null;
    #connectionsChangedHook = null;
    #entitiesChangedHook = null;
    #lastJournal = null;
    #chroniclePanel = null;

    constructor({ locationId = "", activeTab = null, showProfileTab = true, renderProfileExtension = null } = {}) {
        this.#locationId = String(locationId || "");
        this.#showProfileTab = showProfileTab !== false;
        const fallbackTab = this.#showProfileTab ? "profile" : "connections";
        const requestedTab = activeTab ?? DossierTabPreference.getDefaultTab(LocationEntityStore.getLocation(this.#locationId));
        this.#activeTab = this.#normalizeTab(requestedTab, fallbackTab);
        this.#renderProfileExtension = typeof renderProfileExtension === "function" ? renderProfileExtension : null;
        this.#chroniclePanel = new EntityChroniclePanel({ entityId: this.#locationId });
    }

    get locationId() { return this.#locationId; }

    setLocationId(locationId, { activeTab = null } = {}) {
        const nextId = String(locationId || "");
        if (nextId === this.#locationId) return;
        this.#locationId = nextId;
        const fallbackTab = this.#showProfileTab ? "profile" : "connections";
        const requestedTab = activeTab ?? DossierTabPreference.getDefaultTab(LocationEntityStore.getLocation(nextId));
        this.#activeTab = this.#normalizeTab(requestedTab, fallbackTab);
        this.#connectionsBoard = null;
        this.#lastJournal = null;
        this.#chroniclePanel?.setEntityId(nextId);
    }

    async render() {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!entity) {
            return foundry.applications.handlebars.renderTemplate(
                "modules/augur-nexus/templates/campaign-entities/location-embedded-dossier.hbs",
                { missing: true }
            );
        }
        if (!CampaignEntityVisibilityManager.canUserSee(entity, game.user)) return "";
        if (!CampaignEntityDisclosureManager.canUserViewDetails(entity, game.user)) {
            return foundry.applications.handlebars.renderTemplate(
                "modules/augur-nexus/templates/campaign-entities/location-limited-preview.hbs",
                {
                    missing: false,
                    name: LocationEntityModel.getName(entity),
                    imageSrc: LocationEntityModel.getThumbnail(entity) || LocationEntityModel.getImage(entity),
                    accent: LocationEntityModel.getAccent(entity)
                }
            );
        }

        const target = ConnectionTargetResolver.fromCampaignEntity(entity);
        if (!this.#connectionsBoard) this.#connectionsBoard = new ConnectionsBoard({ target, isGM: game.user.isGM });
        else this.#connectionsBoard.setTarget(target);

        const hasChronicle = this.#chroniclePanel.hasEvents();
        if (this.#activeTab === "chronicle" && !hasChronicle) this.#activeTab = this.#showProfileTab ? "profile" : "connections";
        const page = LocationEntityStore.getJournalPage(entity.id);
        this.#lastJournal = { entryId: page?.parent?.id || entity.journalEntryId || "", pageId: page?.id || "" };
        const profile = LocationProfileViewModel.fromEntity(entity, {
            showTabs: false,
            showActions: false,
            showBody: true,
            canRerollCurrentThread: game.user.isGM && canRerollLocationCurrentThread(entity)
        });
        const profileExtensionHtml = this.#showProfileTab && this.#renderProfileExtension
            ? await this.#renderProfileExtension({ entity: foundry.utils.deepClone(entity) })
            : "";

        const chronicleHtml = hasChronicle ? await this.#chroniclePanel.render() : "";
        const connectionsHtml = await foundry.applications.handlebars.renderTemplate(
            "modules/augur-nexus/templates/connections/connections-board.hbs",
            this.#connectionsBoard.getContext()
        );
        return foundry.applications.handlebars.renderTemplate(
            "modules/augur-nexus/templates/campaign-entities/location-embedded-dossier.hbs",
            {
                missing: false,
                isGM: game.user.isGM,
                profile,
                sceneControl: LocationSceneWorkflow.getControlModel(entity.id),
                showProfileTab: this.#showProfileTab,
                hasChronicle,
                chronicleHtml,
                profileExtensionHtml,
                dossier: {
                    isProfileTab: this.#activeTab === "profile",
                    isJournalTab: this.#activeTab === "journal",
                    isConnectionsTab: this.#activeTab === "connections",
                    isChronicleTab: this.#activeTab === "chronicle"
                },
                journal: {
                    hasPage: !!page,
                    hasContent: !!String(page?.text?.content || "").trim(),
                    content: await this.#enrich(page)
                },
                connectionsHtml
            }
        );
    }

    async renderRelationshipSummary() {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!entity || !CampaignEntityDisclosureManager.canUserViewDetails(entity, game.user)) return "";
        const target = this.#getTarget();
        if (!target) return "";
        const ownership = OwnershipService.getOwnership(target);
        if (ownership?.owner.entityType === "faction") {
            const faction = CampaignEntityJournalStore.getFaction(ownership.owner.entityId);
            ownership.color = faction ? FactionEntityModel.getAccent(faction) : "";
        }
        const leadership = LocationLeadershipService.getLeader(target);
        const tradingCenter = TradingCenterService.getTradingCenter(target);
        if (tradingCenter) {
            const flows = ConnectionResourceFlowService.getPerspective(tradingCenter.edge, target.id);
            tradingCenter.sends = flows.sends;
            tradingCenter.receives = flows.receives;
            tradingCenter.hasFlows = flows.hasFlows;
        }
        if (!ownership && !leadership && !tradingCenter) return "";
        return foundry.applications.handlebars.renderTemplate(
            "modules/augur-nexus/templates/campaign-entities/location-relationship-summary.hbs",
            { ownership, leadership, tradingCenter }
        );
    }

    activateListeners(root, hostApplication) {
        this.#watch(hostApplication);
        root?.querySelector?.("[data-action='openLocationOwner']")?.addEventListener("click", async event => {
            event.preventDefault();
            const target = this.#getTarget();
            if (target) await OwnershipService.openOwner(target);
        });
        root?.querySelector?.("[data-action='openLocationLeader']")?.addEventListener("click", async event => {
            event.preventDefault();
            const target = this.#getTarget();
            if (target) await LocationLeadershipService.openLeader(target);
        });
        root?.querySelectorAll?.("[data-action='openLocationTradingCenter']").forEach(button => {
            button.addEventListener("click", async event => {
                event.preventDefault();
                const target = this.#getTarget();
                if (target) await TradingCenterService.openTradingCenter(target);
            });
        });

        const panel = root?.querySelector?.("[data-location-embedded-dossier]");
        if (!panel) return;

        const portrait = panel.querySelector("[data-location-dossier-drag='true']");
        if (portrait && !portrait.dataset.locationDossierDragBound) {
            portrait.dataset.locationDossierDragBound = "true";
            portrait.addEventListener("dragstart", event => {
                const target = this.#getTarget();
                if (!ConnectionTargetResolver.setDragData(event.dataTransfer, target, { effectAllowed: "copy" })) {
                    event.preventDefault();
                    return;
                }
                event.stopPropagation();
                portrait.classList.add("is-dragging");
            });
            portrait.addEventListener("dragend", () => portrait.classList.remove("is-dragging"));
        }

        panel.querySelectorAll("[data-location-dossier-tab]").forEach(button => {
            button.addEventListener("click", event => {
                event.preventDefault();
                this.#activeTab = this.#normalizeTab(event.currentTarget.dataset.locationDossierTab, this.#showProfileTab ? "profile" : "connections");
                hostApplication.render({ parts: ["content"] });
            });
        });


        panel.querySelector("[data-action='openEmbeddedLocationActions']")?.addEventListener("click", event => {
            event.preventDefault();
            this.#openLocationActions(event.currentTarget, hostApplication);
        });

        panel.querySelector("[data-action='openEmbeddedLocationScene']")?.addEventListener("click", async event => {
            event.preventDefault();
            await LocationSceneWorkflow.open(this.#locationId);
        });

        panel.querySelector("[data-action='editEmbeddedLocationJournal']")?.addEventListener("click", async event => {
            event.preventDefault();
            const page = await LocationEntityStore.getOrCreateJournalPage(this.#locationId);
            page?.sheet?.render(true);
        });

        panel.querySelector("[data-action='rerollLocationCurrentThread']")?.addEventListener("click", async event => {
            event.preventDefault();
            event.stopPropagation();
            const button = event.currentTarget;
            if (!game.user.isGM || button.disabled) return;
            button.disabled = true;
            try {
                const updated = await rerollLocationCurrentThread(this.#locationId);
                if (!updated) ui.notifications.warn("This location's generator cannot reroll its Current Thread.");
                hostApplication.render({ parts: ["content"] });
            } catch (error) {
                console.error("Augur Nexus | Failed to reroll location Current Thread", error);
                ui.notifications.error("The Current Thread could not be rerolled.");
            } finally {
                button.disabled = false;
            }
        });

        this.#connectionsBoard?.activateListeners(panel, hostApplication);
        this.#chroniclePanel?.activateListeners(panel, hostApplication);
    }

    matchesCampaignEntityJournal({ entryId, pageId } = {}) {
        if (!this.#lastJournal?.entryId) return false;
        if (pageId) return this.#lastJournal.pageId === pageId;
        return this.#lastJournal.entryId === entryId;
    }

    destroy() {
        CampaignEntityDossierRefresh.unwatch(this.#host);
        if (this.#connectionsChangedHook) Hooks.off("augurNexusConnectionsChanged", this.#connectionsChangedHook);
        if (this.#entitiesChangedHook) Hooks.off("augurNexusCampaignEntitiesChanged", this.#entitiesChangedHook);
        this.#connectionsChangedHook = null;
        this.#entitiesChangedHook = null;
        this.#host = null;
        this.#chroniclePanel?.destroy();
    }

    #openLocationActions(anchor, hostApplication) {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!game.user.isGM || !entity) return;
        const registeredActions = LocationActionRegistry.listFor(entity, {
            onChanged: () => hostApplication.render({ parts: ["content"] })
        });
        openActionMenu({
            anchor,
            className: "location-dossier-actions-menu",
            items: [
                {
                    id: "edit",
                    label: "Edit Location",
                    icon: "fas fa-sliders",
                    onSelect: () => LocationDataEditor.show({
                        locationId: this.#locationId,
                        onSave: () => hostApplication.render({ parts: ["content"] })
                    })
                },
                ...LocationSceneWorkflow.getMenuItems(entity.id, {
                    onChanged: () => hostApplication.render({ parts: ["content"] })
                }),
                {
                    id: "change-cover",
                    label: "Change Cover Image",
                    icon: "fas fa-image",
                    onSelect: () => this.#changeCoverImage(hostApplication)
                },
                {
                    id: "create-shop",
                    label: "New Shop",
                    icon: "fas fa-store",
                    onSelect: () => openShopCreator({
                        locationId: this.#locationId,
                        onSaved: () => hostApplication.render({ parts: ["content"] })
                    })
                },
                ...registeredActions,
                {
                    id: "default-dossier-tab",
                    label: `Default Tab: ${DossierTabPreference.getTabLabel(DossierTabPreference.getDefaultTab(entity))}`,
                    icon: "fas fa-table-columns",
                    onSelect: () => this.#openDefaultDossierTabMenu(anchor, hostApplication)
                },
                {
                    id: "player-location-visibility",
                    label: `Visible To Players: ${CampaignEntityVisibilityManager.getPlayerVisibilityLabel(entity)}`,
                    icon: CampaignEntityVisibilityManager.getPlayerVisibilityIcon(entity),
                    onSelect: () => this.#openLocationVisibilityMenu(anchor, hostApplication)
                },
                {
                    id: "player-location-disclosure",
                    label: `Player Details: ${CampaignEntityDisclosureManager.getPlayerDisclosureLabel(entity, { includeEffective: true })}`,
                    icon: CampaignEntityDisclosureManager.getPlayerDisclosureIcon(entity),
                    onSelect: () => PlayerLocationDisclosureDialog.openEntityMenu({
                        anchor,
                        location: entity,
                        onChanged: () => hostApplication.render({ parts: ["content"] })
                    })
                },
                {
                    id: "delete",
                    label: "Delete Location",
                    status: "Permanent",
                    icon: "fas fa-skull-crossbones",
                    danger: true,
                    className: "permanent-danger",
                    onSelect: () => this.#deleteLocation(hostApplication)
                }
            ]
        });
    }

    #openDefaultDossierTabMenu(anchor, hostApplication) {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!game.user.isGM || !entity) return;
        openActionMenu({
            anchor,
            className: "location-dossier-actions-menu",
            items: DossierTabPreference.buildMenuItems(
                DossierTabPreference.getDefaultTab(entity),
                tab => this.#setDefaultDossierTab(tab, hostApplication)
            )
        });
    }

    async #setDefaultDossierTab(tab, hostApplication) {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!game.user.isGM || !entity) return;
        const defaultTab = DossierTabPreference.normalizeTab(tab);
        await LocationEntityStore.updateLocation(entity.id, { dossier: { defaultTab } });
        this.#activeTab = defaultTab;
        hostApplication.render({ parts: ["content"] });
    }

    #openLocationVisibilityMenu(anchor, hostApplication) {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!game.user.isGM || !entity) return;
        const current = CampaignEntityVisibilityManager.getPlayerVisibilityOverride(entity);
        openActionMenu({
            anchor,
            className: "nexus-scene-player-access-menu",
            items: [
                { id: "inherit", label: current === "inherit" ? "Global (Current)" : "Global", icon: "fas fa-layer-group", onSelect: () => this.#setLocationPlayerVisibility("inherit", hostApplication) },
                { id: "show", label: current === "show" ? "Yes (Current)" : "Yes", icon: "fas fa-eye", onSelect: () => this.#setLocationPlayerVisibility("show", hostApplication) },
                { id: "hide", label: current === "hide" ? "No (Current)" : "No", icon: "fas fa-eye-slash", onSelect: () => this.#setLocationPlayerVisibility("hide", hostApplication) },
                { id: "change-global", label: "Change Global Setting...", icon: "fas fa-sliders", onSelect: () => PlayerNpcVisibilityDialog.show("location") },
                { id: "player-visibility-info", label: "What's this?", icon: "fas fa-circle-info", onSelect: () => PlayerVisibilityInfoPanel.show("campaignEntityVisibility") }
            ]
        });
    }

    async #setLocationPlayerVisibility(value, hostApplication) {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!game.user.isGM || !entity) return;
        await CampaignEntityVisibilityManager.setPlayerVisibilityOverride(entity.id, "location", value);
        hostApplication.render({ parts: ["content"] });
    }

    async #deleteLocation(hostApplication) {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!game.user.isGM || !entity) return;
        if (await deleteLocation(entity.id)) await hostApplication.close();
    }

    #changeCoverImage(hostApplication) {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!game.user.isGM || !entity) return;
        SiteCoverPicker.show({
            current: LocationEntityModel.getCoverImage(entity),
            onSelect: path => this.#setCoverImage(path || "", hostApplication)
        });
    }

    async #setCoverImage(path, hostApplication) {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        if (!game.user.isGM || !entity) return;
        await LocationEntityStore.updateLocation(entity.id, { display: { coverImageSrc: path || "" } });
        hostApplication.render({ parts: ["content"] });
    }

    #watch(hostApplication) {
        if (!hostApplication || this.#host === hostApplication) return;
        this.destroy();
        this.#host = hostApplication;
        this.#connectionsChangedHook = () => hostApplication.render({ parts: ["content"] });
        this.#entitiesChangedHook = event => {
            const entity = event?.entity || null;
            const owner = entity?.type === "faction"
                ? OwnershipService.getOwnership(this.#getTarget(), { includeHidden: true })?.owner
                : null;
            const leader = entity?.type === "npc"
                ? LocationLeadershipService.getLeader(this.#getTarget(), { includeHidden: true })?.leader
                : null;
            if (!entity || entity.id === this.#locationId || owner?.entityId === entity.id || leader?.entityId === entity.id) {
                hostApplication.render({ parts: ["content"] });
            }
        };
        Hooks.on("augurNexusConnectionsChanged", this.#connectionsChangedHook);
        Hooks.on("augurNexusCampaignEntitiesChanged", this.#entitiesChangedHook);
        CampaignEntityDossierRefresh.watch(hostApplication);
    }

    #normalizeTab(value, fallback) {
        const tab = String(value || "");
        if (!["profile", "journal", "connections", "chronicle"].includes(tab)) return fallback;
        if (tab === "profile" && !this.#showProfileTab) return fallback;
        return tab;
    }

    #getTarget() {
        const entity = LocationEntityStore.getLocation(this.#locationId);
        return entity ? ConnectionTargetResolver.fromCampaignEntity(entity) : null;
    }

    async #enrich(page) {
        const content = page?.text?.content || "";
        if (!String(content).trim()) return "";
        try {
            return foundry.applications.ux.TextEditor.implementation.enrichHTML(content, { relativeTo: page, secrets: page.isOwner });
        } catch (_error) {
            return content;
        }
    }
}
