import { LocationEntityModel } from "../../campaign-entities/models/LocationEntityModel.js";
import { LocationEntityStore } from "../../campaign-entities/services/LocationEntityStore.js";
import { ShopPresetRegistry } from "./ShopPresetRegistry.js";
import { ShopStore } from "./ShopStore.js";

export class ShopDerivedNameService {
    static #syncQueueByLocationId = new Map();

    static registerHooks() {
        Hooks.on("augurNexusCampaignEntitiesChanged", ({ entity } = {}) => {
            if (entity?.type !== "location" || !this.#isResponsibleGM()) return;
            void this.syncForLocation(entity.id).catch(error => {
                console.error("Augur Nexus | Failed to synchronize derived Shop names.", error);
            });
        });
        Hooks.once("augurNexusCampaignEntitiesReady", () => {
            if (!this.#isResponsibleGM()) return;
            void this.#reconcileUnmanagedEditorShops().catch(error => {
                console.error("Augur Nexus | Failed to reconcile manually created Shop names.", error);
            });
        });
    }

    static getState(idOrShop) {
        const shop = typeof idOrShop === "string" ? ShopStore.getShop(idOrShop) : idOrShop;
        if (!shop) return null;
        const parent = ShopStore.getParentLocation(shop);
        const generatedName = parent ? this.render(shop.naming?.pattern, LocationEntityModel.getName(parent)) : "";
        return {
            mode: shop.naming?.mode || "unmanaged",
            isDerived: shop.naming?.mode === "derived",
            isCustom: shop.naming?.mode === "custom",
            templateId: String(shop.naming?.templateId || ""),
            pattern: String(shop.naming?.pattern || ""),
            parentNameSnapshot: String(shop.naming?.parentNameSnapshot || ""),
            generatedName,
            canRestore: !!parent && !!generatedName && !!shop.naming?.pattern
        };
    }

    static render(pattern = "", parentName = "") {
        const source = String(pattern || "").trim();
        const parent = String(parentName || "").trim();
        if (!source || !parent) return "";
        return source.replaceAll("{parent}", parent).replace(/\s+/g, " ").trim();
    }

    static async syncForLocation(locationId) {
        if (!this.#isResponsibleGM()) return [];
        const id = String(locationId || "").trim();
        if (!id) return [];
        const previous = this.#syncQueueByLocationId.get(id) || Promise.resolve([]);
        const operation = previous.catch(() => []).then(() => this.#syncCurrentLocation(id));
        this.#syncQueueByLocationId.set(id, operation);
        try { return await operation; }
        finally {
            if (this.#syncQueueByLocationId.get(id) === operation) this.#syncQueueByLocationId.delete(id);
        }
    }

    static async restore(idOrShop) {
        if (!game.user?.isGM) return null;
        const shop = typeof idOrShop === "string" ? ShopStore.getShop(idOrShop) : idOrShop;
        const state = this.getState(shop);
        const parent = shop ? ShopStore.getParentLocation(shop) : null;
        if (!shop || !parent || !state?.canRestore) return null;
        return ShopStore.updateShop(shop.id, {
            name: state.generatedName,
            naming: {
                ...shop.naming,
                mode: "derived",
                parentNameSnapshot: LocationEntityModel.getName(parent)
            }
        }, { nameIntent: "derived" });
    }

    static async #syncCurrentLocation(locationId) {
        const location = LocationEntityStore.getLocation(locationId);
        if (!location) return [];
        const parentName = LocationEntityModel.getName(location);
        const updated = [];
        for (const shop of ShopStore.getShopsForParentLocation(location.id)) {
            if (shop.naming?.mode !== "derived") continue;
            const nextName = this.render(shop.naming?.pattern, parentName);
            if (!nextName) continue;
            if (shop.name === nextName && shop.naming?.parentNameSnapshot === parentName) continue;
            updated.push(await ShopStore.updateShop(shop.id, {
                name: nextName,
                naming: {
                    ...shop.naming,
                    mode: "derived",
                    parentNameSnapshot: parentName
                }
            }, { nameIntent: "derived" }));
        }
        return updated;
    }

    static async #reconcileUnmanagedEditorShops() {
        for (const shop of ShopStore.getShops()) {
            if (shop.naming?.mode !== "unmanaged" || shop.source?.moduleId) continue;
            const parent = ShopStore.getParentLocation(shop);
            if (!parent) continue;
            const preset = ShopPresetRegistry.get(shop.restockProfile?.preset?.id);
            const suffix = preset?.name || "Shop";
            const parentName = LocationEntityModel.getName(parent);
            const generatedName = `${parentName} ${suffix}`;
            await ShopStore.updateShop(shop.id, {
                naming: {
                    mode: shop.name === generatedName ? "derived" : "custom",
                    templateId: `augur-nexus:location-shop:${preset?.id || "generic"}`,
                    pattern: `{parent} ${suffix}`,
                    parentNameSnapshot: parentName
                }
            });
        }
    }

    static #isResponsibleGM() {
        if (!game.user?.isGM) return false;
        const activeGM = game.users?.activeGM || game.users?.find(user => user.active && user.isGM);
        return !activeGM || activeGM.id === game.user.id;
    }
}
