import { getLocation, openLocation, updateLocation } from "/modules/augur-nexus/scripts/api/locations.js";
import { RegionalTradeNetworkModel } from "../models/RegionalTradeNetworkModel.js";
import { TradeGoodsPickerApplication } from "./TradeGoodsPickerApplication.js";
import { TradeGoodsCatalogApplication } from "./TradeGoodsCatalogApplication.js";
import { TradeRegionSceneService } from "../services/TradeRegionSceneService.js";
import { TradeRouteService } from "../services/TradeRouteService.js";

const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
const MODULE_ID = "augur-nexus";

export class RegionalTradeNetworkApplication extends HandlebarsApplicationMixin(ApplicationV2) {
    #focusLocationId = "";
    #factionId = "";
    #selectedLocationId = "";
    #scope = "connected";
    #sceneId = "";
    #model = null;
    #connectionsChangedHook = null;
    #entitiesChangedHook = null;
    #tradeGoodsChangedHook = null;
    #positionInitialized = false;
    #suspendRefresh = false;

    static DEFAULT_OPTIONS = {
        id: "augur-nexus-regional-trade-network",
        classes: ["augur-nexus", "augur-theme-fantasy", "regional-trade-network"],
        tag: "div",
        window: { title: "Regional Trade Network", resizable: true, minimizable: true },
        position: { width: 1420, height: 780 },
        actions: {
            setTradeScope: RegionalTradeNetworkApplication._onSetScope,
            selectTradeLocation: RegionalTradeNetworkApplication._onSelectLocation,
            openTradeLocation: RegionalTradeNetworkApplication._onOpenLocation,
            manageTradeGoods: RegionalTradeNetworkApplication._onManageTradeGoods,
            clearTradeRoute: RegionalTradeNetworkApplication._onClearRoute,
            editTradeGoods: RegionalTradeNetworkApplication._onEditGoods
        }
    };

    static PARTS = { content: { template: "modules/augur-nexus/templates/trade/regional-trade-network.hbs" } };

    static async show({ locationId = "", factionId = "", scope = "", sceneId = "" } = {}) {
        const resolvedSceneId = locationId
            ? await TradeRegionSceneService.chooseSceneId(locationId, { sceneId })
            : String(sceneId || globalThis.canvas?.scene?.id || "");
        if (!resolvedSceneId && factionId) {
            ui.notifications.warn("Open a regional Scene before inspecting this Faction's trade network.");
            return null;
        }
        const app = new this({ locationId, factionId, scope, sceneId: resolvedSceneId });
        app.render(true, { focus: true });
        return app;
    }

    constructor({ locationId = "", factionId = "", scope = "", sceneId = "" } = {}, options = {}) {
        super(options);
        this.#focusLocationId = String(locationId || "");
        this.#factionId = String(factionId || "");
        this.#selectedLocationId = this.#focusLocationId;
        this.#scope = scope || (this.#factionId ? "faction" : "connected");
        this.#sceneId = String(sceneId || "");
        this.#connectionsChangedHook = () => this.#refresh();
        this.#entitiesChangedHook = ({ entity } = {}) => {
            if (!entity || entity.type === "location") this.#refresh();
        };
        Hooks.on("augurNexusConnectionsChanged", this.#connectionsChangedHook);
        Hooks.on("augurNexusCampaignEntitiesChanged", this.#entitiesChangedHook);
        this.#tradeGoodsChangedHook = () => this.#refresh();
        Hooks.on("augurNexusTradeGoodsChanged", this.#tradeGoodsChangedHook);
    }

    async _prepareContext() {
        this.#model = await RegionalTradeNetworkModel.build({
            focusLocationId: this.#focusLocationId,
            factionId: this.#factionId,
            selectedLocationId: this.#selectedLocationId,
            scope: this.#scope,
            sceneId: this.#sceneId
        });
        this.#sceneId = this.#model.sceneId || "";
        this.#selectedLocationId = this.#model.selectedLocationId || "";
        return this.#model;
    }

    _onRender(context, options) {
        super._onRender(context, options);
        if (!this.#positionInitialized) {
            const width = Math.min(1420, window.innerWidth - 40);
            const height = Math.min(780, window.innerHeight - 40);
            this.setPosition({
                width,
                height,
                left: Math.max(20, Math.round((window.innerWidth - width) / 2)),
                top: Math.max(20, Math.round((window.innerHeight - height) / 2))
            });
            this.#positionInitialized = true;
        }
        this.element.querySelector("[name='tradingCenter.entityId']")?.addEventListener("change", event => {
            void this.#changeTradingCenter(String(event.currentTarget.value || ""), event.currentTarget);
        });
    }

    async close(options) {
        if (this.#connectionsChangedHook) Hooks.off("augurNexusConnectionsChanged", this.#connectionsChangedHook);
        if (this.#entitiesChangedHook) Hooks.off("augurNexusCampaignEntitiesChanged", this.#entitiesChangedHook);
        if (this.#tradeGoodsChangedHook) Hooks.off("augurNexusTradeGoodsChanged", this.#tradeGoodsChangedHook);
        return super.close(options);
    }

    static _onSetScope(_event, target) {
        const scope = String(target?.dataset?.scope || "");
        if (!scope || scope === this.#scope) return;
        this.#scope = scope;
        this.render({ parts: ["content"] });
    }

    static _onSelectLocation(_event, target) {
        const locationId = String(target?.dataset?.locationId || "");
        if (!locationId || locationId === this.#selectedLocationId) return;
        this.#selectedLocationId = locationId;
        this.render({ parts: ["content"] });
    }

    static _onOpenLocation(_event, target) {
        const locationId = String(target?.dataset?.locationId || this.#selectedLocationId || "");
        if (locationId) return openLocation(locationId);
    }

    static _onManageTradeGoods() { return TradeGoodsCatalogApplication.show(); }
    static _onClearRoute(_event, target) { return this.#clearRoute(target); }
    static _onEditGoods(_event, target) { this.#editGoods(String(target?.dataset?.goodsField || "")); }

    async #changeTradingCenter(centerEntityId, control = null) {
        if (!game.user?.isGM || control?.disabled) return;
        if (control) control.disabled = true;
        try {
            this.#suspendRefresh = true;
            await TradeRouteService.changeTradingCenter({
                locationId: this.#selectedLocationId,
                centerLocationId: centerEntityId,
                sceneId: this.#sceneId
            });
        } catch (error) {
            console.error("Augur: Nexus | Failed to update Regional Trade Network", error);
            ui.notifications.error(error?.message || "The trade network could not be updated.");
        } finally {
            this.#suspendRefresh = false;
            if (control) control.disabled = false;
            this.#refresh();
        }
    }

    async #clearRoute(button) {
        return this.#changeTradingCenter("", button);
    }

    #editGoods(field) {
        if (!game.user?.isGM || field !== "produces") return;
        const labels = { produces: "Goods Produced Here" };
        TradeGoodsPickerApplication.show({
            title: labels[field],
            goods: this.#model?.selected?.goods || [],
            selectedIds: (this.#model?.selected?.producedGoods || []).map(good => good.id),
            onApply: selectedIds => void this.#updateProduction(selectedIds)
        });
    }

    async #updateProduction(selectedIds) {
        if (!game.user?.isGM) return;
        const entity = getLocation(this.#selectedLocationId);
        if (!entity) return;
        const produces = [...new Set((selectedIds || []).map(String).filter(Boolean))];
        const economy = { schemaVersion: 1, produces: produces.map(goodId => ({ goodId })) };
        try {
            this.#suspendRefresh = true;
            await updateLocation(entity.id, { economy }, { syncMarkers: false });
            await this.#reconcileRegionalMarkets();
        } catch (error) {
            console.error("Augur: Nexus | Failed to update local production", error);
            ui.notifications.error(error?.message || "Local production could not be updated.");
        } finally {
            this.#suspendRefresh = false;
            this.#refresh();
        }
    }

    async #reconcileRegionalMarkets() {
        await TradeRouteService.reconcileRegionalMarkets({
            sceneId: this.#sceneId,
            fallbackLocationId: this.#selectedLocationId
        });
    }

    #refresh() {
        if (!this.#suspendRefresh && this.rendered !== false) this.render({ parts: ["content"] });
    }
}
