import { DossierTabPreference } from "../../nexus/services/DossierTabPreference.js";
import { LocationParentReference } from "../models/LocationParentReference.js";
import { LOCATION_DOSSIER_VIEW_IDS } from "./LocationDossierViewIds.js";

const MODULE_ID = "augur-nexus";
const DEFAULT = {
    type: "location",
    schemaVersion: 8,
    sourceModule: MODULE_ID,
    display: { name: "New Location", imageSrc: "", thumbnailSrc: "", coverImageSrc: "", color: "#d18a42" },
    profile: { kindId: "location", kindLabel: "Location", type: "", summary: "", fields: [] },
    currentThread: { state: "", pressure: "", opportunity: "", secret: "" },
    hierarchy: { parent: null },
    scenes: { primarySceneId: null },
    access: { playerVisibility: "inherit", playerDisclosure: "inherit" },
    dossier: { defaultTab: "profile", viewId: "" },
    tags: [],
    generation: { generatorId: "", templateId: "", seed: null },
    economy: { schemaVersion: 2, produces: [] },
    markerRefs: [],
    moduleData: {}
};

export class LocationEntityNormalizer {
    static async normalizeForCreate(data = {}) {
        const now = Date.now();
        return this.#normalize({ ...DEFAULT, ...data, id: this.#id(data.id), createdTime: now, updatedTime: now });
    }

    static async normalizeForUpdate(current = {}, patch = {}, { moduleId = "" } = {}) {
        const next = foundry.utils.deepClone(current);
        const groups = {
            display: ["name", "imageSrc", "thumbnailSrc", "coverImageSrc", "color"],
            profile: ["kindId", "kindLabel", "type", "summary", "fields"],
            currentThread: ["state", "pressure", "opportunity", "secret"],
            hierarchy: ["parent"],
            scenes: ["primarySceneId"],
            access: ["playerVisibility", "playerDisclosure"],
            dossier: ["defaultTab", "viewId"],
            generation: ["generatorId", "templateId", "seed"],
            economy: ["schemaVersion", "produces"]
        };
        for (const [key, value] of Object.entries(patch || {})) {
            if (["tags", "markerRefs"].includes(key)) {
                next[key] = value;
                continue;
            }
            if (key === "moduleData") {
                if (!moduleId) throw new Error("Location moduleData updates require moduleId.");
                next.moduleData = { ...(next.moduleData || {}), [moduleId]: value?.[moduleId] || {} };
                continue;
            }
            if (!groups[key] || !value || typeof value !== "object") throw new Error(`Unsupported location update field: ${key}`);
            next[key] = next[key] || {};
            for (const field of groups[key]) {
                if (Object.hasOwn(value, field)) next[key][field] = foundry.utils.deepClone(value[field]);
            }
        }
        next.updatedTime = Date.now();
        return this.#normalize(next);
    }

    static normalizeExisting(entity = {}) {
        return this.#normalize({ ...DEFAULT, ...entity, id: this.#id(entity.id) });
    }

    static #normalize(entity) {
        const text = value => String(value || "").trim();
        const fields = (Array.isArray(entity.profile?.fields) ? entity.profile.fields : [])
            .map(field => ({
                id: text(field.id) || `field.${foundry.utils.randomID()}`,
                label: text(field.label),
                value: text(field.value),
                type: field.type === "multiline" ? "multiline" : "text"
            }))
            .filter(field => field.label);
        return {
            id: this.#id(entity.id),
            type: "location",
            schemaVersion: 8,
            sourceModule: text(entity.sourceModule || MODULE_ID),
            createdTime: Number(entity.createdTime || Date.now()),
            updatedTime: Number(entity.updatedTime || Date.now()),
            display: {
                name: text(entity.display?.name || "New Location") || "New Location",
                imageSrc: text(entity.display?.imageSrc),
                thumbnailSrc: text(entity.display?.thumbnailSrc),
                coverImageSrc: text(entity.display?.coverImageSrc),
                color: /^#[0-9a-f]{6}$/i.test(text(entity.display?.color)) ? text(entity.display.color) : "#d18a42"
            },
            profile: {
                kindId: text(entity.profile?.kindId || "location"),
                kindLabel: text(entity.profile?.kindLabel || "Location"),
                type: text(entity.profile?.type),
                summary: text(entity.profile?.summary),
                fields
            },
            currentThread: {
                state: text(entity.currentThread?.state),
                pressure: text(entity.currentThread?.pressure),
                opportunity: text(entity.currentThread?.opportunity),
                secret: text(entity.currentThread?.secret)
            },
            hierarchy: { parent: LocationParentReference.normalize(entity.hierarchy?.parent) },
            scenes: { primarySceneId: text(entity.scenes?.primarySceneId) || null },
            access: {
                playerVisibility: ["inherit", "show", "hide"].includes(entity.access?.playerVisibility) ? entity.access.playerVisibility : "inherit",
                playerDisclosure: ["inherit", "limited", "full"].includes(entity.access?.playerDisclosure) ? entity.access.playerDisclosure : "inherit"
            },
            dossier: {
                defaultTab: DossierTabPreference.normalizeTab(entity.dossier?.defaultTab),
                viewId: this.#dossierViewId(entity, text)
            },
            tags: [...new Set((entity.tags || []).map(text).filter(Boolean))],
            generation: {
                generatorId: text(entity.generation?.generatorId),
                templateId: text(entity.generation?.templateId),
                seed: entity.generation?.seed ?? null
            },
            economy: {
                schemaVersion: Math.max(2, Number(entity.economy?.schemaVersion || 2)),
                produces: [...new Set((Array.isArray(entity.economy?.produces) ? entity.economy.produces : [])
                    .map(entry => String(entry?.goodId || entry || "").trim())
                    .filter(Boolean))].map(goodId => ({ goodId }))
            },
            markerRefs: Array.isArray(entity.markerRefs) ? foundry.utils.deepClone(entity.markerRefs) : [],
            moduleData: entity.moduleData && typeof entity.moduleData === "object" ? foundry.utils.deepClone(entity.moduleData) : {}
        };
    }

    static #id(value) {
        const id = String(value || "").trim();
        return id.startsWith("location.") ? id : `location.${id || foundry.utils.randomID()}`;
    }

    static #dossierViewId(entity, text) {
        const explicit = text(entity.dossier?.viewId);
        if (explicit) return explicit;

        const legacyViewIds = new Set(["settlement-dossier", "location-experience"]);
        const usesLegacySettlementView = Object.values(entity.moduleData || {})
            .some(moduleData => legacyViewIds.has(text(moduleData?.presentation?.viewId)));
        return usesLegacySettlementView ? LOCATION_DOSSIER_VIEW_IDS.settlement : "";
    }
}
