import { TradeGoodsCatalog } from "../services/TradeGoodsCatalog.js";
import { TradeGoodEditorApplication } from "./TradeGoodEditorApplication.js";

const { ApplicationV2, HandlebarsApplicationMixin, DialogV2 } = foundry.applications.api;

export class TradeGoodsCatalogApplication extends HandlebarsApplicationMixin(ApplicationV2) {
    static #instance = null;
    #query = "";
    #catalogChangedHook = null;

    static DEFAULT_OPTIONS = {
        id: "augur-nexus-trade-goods-catalog",
        classes: ["augur-nexus", "augur-theme-fantasy", "trade-goods-catalog-window"],
        tag: "div",
        window: { title: "Trade Goods & Prices", resizable: true, minimizable: true },
        position: { width: 900, height: 700 },
        actions: {
            addCustomGood: TradeGoodsCatalogApplication._onAddCustomGood,
            editCustomGood: TradeGoodsCatalogApplication._onEditCustomGood,
            resetGoodPrice: TradeGoodsCatalogApplication._onResetGoodPrice,
            resetAllPrices: TradeGoodsCatalogApplication._onResetAllPrices,
            archiveCustomGood: TradeGoodsCatalogApplication._onArchiveCustomGood,
            restoreCustomGood: TradeGoodsCatalogApplication._onRestoreCustomGood
        }
    };

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

    static show() {
        if (!game.user?.isGM) return null;
        if (!this.#instance || this.#instance.rendered === false) this.#instance = new this();
        this.#instance.render(true, { focus: true });
        return this.#instance;
    }

    constructor(options = {}) {
        super(options);
        this.#catalogChangedHook = () => this.rendered !== false && this.render({ parts: ["content"] });
        Hooks.on("augurNexusTradeGoodsChanged", this.#catalogChangedHook);
    }

    async _prepareContext() {
        const goods = await TradeGoodsCatalog.getGoods({ includeArchived: true });
        const world = TradeGoodsCatalog.getWorldCatalog();
        const marketRates = TradeGoodsCatalog.getMarketRates();
        const overridden = new Set(Object.entries(world.overrides || {})
            .filter(([, value]) => Object.hasOwn(value || {}, "tradeValue"))
            .map(([id]) => id));
        return {
            query: this.#query,
            marketRates: {
                sourcePercent: Math.round(marketRates.sourceMultiplier * 100),
                cityImportPercent: Math.round(marketRates.cityImportMultiplier * 100)
            },
            goods: goods.map(good => ({
                ...good,
                familyLabel: this.#label(good.familyId),
                sourceLabel: good.custom ? "Custom" : "Standard",
                overridden: !good.custom && overridden.has(good.id),
                searchText: `${good.name} ${good.familyId} ${good.lot?.label || ""} ${good.custom ? "custom" : "standard built-in"}`.toLocaleLowerCase()
            })),
            activeCount: goods.filter(good => !good.archived).length,
            customCount: goods.filter(good => good.custom && !good.archived).length,
            hasOverrides: overridden.size > 0
        };
    }

    _onRender(context, options) {
        super._onRender(context, options);
        const search = this.element.querySelector("[data-trade-catalog-search]");
        search?.addEventListener("input", event => {
            this.#query = String(event.currentTarget.value || "");
            this.#applySearch();
        });
        this.element.querySelectorAll("[data-trade-good-price]").forEach(input => {
            input.addEventListener("change", () => void this.#savePrice(input));
            input.addEventListener("keydown", event => {
                if (event.key === "Enter") { event.preventDefault(); input.blur(); }
            });
        });
        this.element.querySelectorAll("[data-trade-rate]").forEach(input => {
            input.addEventListener("change", () => void this.#saveMarketRates());
            input.addEventListener("keydown", event => {
                if (event.key === "Enter") { event.preventDefault(); input.blur(); }
            });
        });
        this.#applySearch();
    }

    async close(options) {
        if (this.#catalogChangedHook) Hooks.off("augurNexusTradeGoodsChanged", this.#catalogChangedHook);
        if (TradeGoodsCatalogApplication.#instance === this) TradeGoodsCatalogApplication.#instance = null;
        return super.close(options);
    }

    static _onAddCustomGood() {
        TradeGoodEditorApplication.show({ onSaved: () => this.render({ parts: ["content"] }) });
    }

    static async _onEditCustomGood(_event, target) {
        const good = await TradeGoodsCatalog.getGood(target?.dataset?.goodId);
        if (!good?.custom) return;
        TradeGoodEditorApplication.show({ good, onSaved: () => this.render({ parts: ["content"] }) });
    }

    static async _onResetGoodPrice(_event, target) {
        await TradeGoodsCatalog.resetPrice(target?.dataset?.goodId);
    }

    static async _onResetAllPrices() {
        const confirmed = await DialogV2.confirm({
            window: { title: "Reset Default Prices?" },
            content: "<p>Restore the default price for every standard trade good? Custom goods will not be changed.</p>",
            yes: { label: "Reset Prices", icon: "fas fa-rotate-left" },
            no: { label: "Cancel" },
            rejectClose: false
        });
        if (confirmed) await TradeGoodsCatalog.resetAllPrices();
    }

    static async _onArchiveCustomGood(_event, target) {
        const good = await TradeGoodsCatalog.getGood(target?.dataset?.goodId);
        if (!good?.custom) return;
        const confirmed = await DialogV2.confirm({
            window: { title: `Archive ${good.name}?` },
            content: "<p>This good will disappear from production pickers but remain available to existing Locations and Shops that already reference it.</p>",
            yes: { label: "Archive", icon: "fas fa-box-archive" },
            no: { label: "Cancel" },
            rejectClose: false
        });
        if (confirmed) await TradeGoodsCatalog.setCustomArchived(good.id, true);
    }

    static async _onRestoreCustomGood(_event, target) {
        await TradeGoodsCatalog.setCustomArchived(target?.dataset?.goodId, false);
    }

    async #savePrice(input) {
        if (input.disabled) return;
        const value = Number(input.value);
        if (!Number.isFinite(value) || value < 0) {
            ui.notifications.warn("Trade value must be zero or greater.");
            return this.render({ parts: ["content"] });
        }
        input.disabled = true;
        try { await TradeGoodsCatalog.setPrice(input.dataset.goodId, value); }
        catch (error) {
            console.error("Augur: Nexus | Failed to update trade-good price", error);
            ui.notifications.error(error?.message || "The trade-good price could not be updated.");
            this.render({ parts: ["content"] });
        }
    }

    async #saveMarketRates() {
        const inputs = [...this.element.querySelectorAll("[data-trade-rate]")];
        const percent = name => Number(this.element.querySelector(`[name="${name}"]`)?.value);
        const sourcePercent = percent("sourcePercent");
        const cityImportPercent = percent("cityImportPercent");
        const sourceValid = Number.isFinite(sourcePercent) && sourcePercent >= 0 && sourcePercent <= 500;
        const cityValid = Number.isFinite(cityImportPercent) && cityImportPercent >= 100 && cityImportPercent <= 500;
        if (!sourceValid || !cityValid) {
            ui.notifications.warn("Local export price must be between 0% and 500%; city demand price must be between 100% and 500%.");
            return this.render({ parts: ["content"] });
        }
        inputs.forEach(input => { input.disabled = true; });
        try {
            await TradeGoodsCatalog.setMarketRates({
                sourceMultiplier: sourcePercent / 100,
                cityImportMultiplier: cityImportPercent / 100
            });
        } catch (error) {
            console.error("Augur: Nexus | Failed to update global trade rates", error);
            ui.notifications.error(error?.message || "The global trade rates could not be updated.");
            this.render({ parts: ["content"] });
        }
    }

    #applySearch() {
        const query = this.#query.trim().toLocaleLowerCase();
        for (const row of this.element?.querySelectorAll?.("[data-trade-catalog-good]") || []) {
            row.hidden = !!query && !String(row.dataset.searchText || "").includes(query);
        }
    }

    #label(value) {
        return String(value || "Trade good").replace(/-/g, " ").replace(/\b\w/g, letter => letter.toLocaleUpperCase());
    }
}
