import { CampaignEntityFolderManager } from "../../campaign-entities/services/CampaignEntityFolderManager.js";
import { RegionPopulationRunStore } from "./RegionPopulationRunStore.js";
import { RegionChronicleIndex } from "./RegionChronicleIndex.js";
import { ChronicleNarrativeModel } from "../models/ChronicleNarrativeModel.js";

const MODULE_ID = "augur-nexus";
const ENTRY_SUFFIX = "Regional Chronicle";
const SCHEMA_VERSION = 2;

export class RegionChronicleService {
    static getEntry(scene, run = null) {
        run ||= RegionPopulationRunStore.get(scene);
        const entryId = String(run?.chronicleJournalEntryId || "").trim();
        return scene?.id && entryId ? game.journal.get(entryId) || null : null;
    }

    static getData(scene, run = null) {
        const entry = this.getEntry(scene, run);
        const data = entry?.flags?.[MODULE_ID]?.chronicle;
        return data ? foundry.utils.deepClone(data) : null;
    }

    static async create(scene, { runId = "", data = {} } = {}) {
        if (!scene?.id) throw new Error("A Scene is required to create a regional chronicle.");
        const folder = await CampaignEntityFolderManager.getOrCreateChronicleFolder();
        const chronicle = this.#normalizeData(scene, runId, data);
        const entry = await JournalEntry.create({
            name: this.#entryName(scene.name),
            folder: folder?.id || null,
            ownership: { default: CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER },
            flags: {
                [MODULE_ID]: {
                    regionChronicle: true,
                    sceneId: scene.id,
                    sceneName: scene.name,
                    runId: String(runId || ""),
                    chronicle
                }
            }
        });
        this.#notify("create", scene.id, entry.id);
        return { entry, data: foundry.utils.deepClone(chronicle) };
    }

    static async append(scene, { runId = "", data = {} } = {}) {
        const entry = this.getEntry(scene);
        if (!entry) return this.create(scene, { runId, data });
        const current = foundry.utils.deepClone(entry.flags?.[MODULE_ID]?.chronicle || {});
        const incoming = foundry.utils.deepClone(data || {});
        const events = [
            ...(current.events || []),
            ...(incoming.events || []).map(event => ({ ...event, runId: String(event?.runId || runId || "") }))
        ];
        const chronicle = this.#normalizeData(scene, runId, {
            ...current,
            ...incoming,
            years: Math.max(Number(current.years || 0), Number(incoming.years || 0)),
            partial: incoming.partial === true,
            summary: { ...(current.summary || {}), ...(incoming.summary || {}) },
            events
        });
        await entry.update({
            [`flags.${MODULE_ID}.runId`]: String(runId || ""),
            [`flags.${MODULE_ID}.chronicle`]: chronicle
        });
        this.#notify("append", scene.id, entry.id);
        return { entry, data: foundry.utils.deepClone(chronicle) };
    }

    static async update({ entry }, { data = {} } = {}) {
        if (!entry) return null;
        const sceneId = String(entry.flags?.[MODULE_ID]?.sceneId || data.sceneId || "");
        const scene = game.scenes.get(sceneId) || null;
        const runId = String(entry.flags?.[MODULE_ID]?.runId || data.runId || "");
        const chronicle = this.#normalizeData(scene, runId, data);
        await entry.update({ [`flags.${MODULE_ID}.chronicle`]: chronicle });
        this.#notify("update", sceneId, entry.id);
        return { entry, data: foundry.utils.deepClone(chronicle) };
    }

    static async open(scene, run = null) {
        if (!this.getEntry(scene, run)) return false;
        const { RegionChronicleApplication } = await import("../applications/RegionChronicleApplication.js");
        RegionChronicleApplication.show({ sceneId: scene.id });
        return true;
    }

    static async delete(scene, run = null) {
        const entry = this.getEntry(scene, run);
        if (!entry) return false;
        const sceneId = scene.id;
        const entryId = entry.id;
        await entry.delete();
        this.#notify("delete", sceneId, entryId);
        return true;
    }

    static async rename(scene, nextName, run = null) {
        const entry = this.getEntry(scene, run);
        if (!entry) return false;
        const name = String(nextName || "Region").trim() || "Region";
        const chronicle = foundry.utils.deepClone(entry.flags?.[MODULE_ID]?.chronicle || {});
        chronicle.sceneName = name;
        await entry.update({
            name: this.#entryName(name),
            [`flags.${MODULE_ID}.sceneName`]: name,
            [`flags.${MODULE_ID}.chronicle`]: chronicle
        });
        this.#notify("rename", scene.id, entry.id);
        return true;
    }

    static refreshAvailability(scene) {
        if (!scene?.id) return;
        this.#notify("availability", scene.id, this.getEntry(scene)?.id || "");
    }

    static notifyExternalDeletion(document) {
        if (!this.isChronicle(document)) return;
        this.#notify("delete", String(document.flags?.[MODULE_ID]?.sceneId || ""), String(document.id || ""));
    }
    static isChronicle(document) {
        return document?.flags?.[MODULE_ID]?.regionChronicle === true;
    }

    static #notify(reason, sceneId, entryId) {
        RegionChronicleIndex.invalidate();
        Hooks.callAll("augurNexusRegionChronicleChanged", { reason, sceneId, entryId });
        if (ui.controls?.render) void ui.controls.render({ reset: true });
    }
    static #entryName(sceneName) {
        return `${String(sceneName || "Region").trim() || "Region"} — ${ENTRY_SUFFIX}`;
    }

    static #normalizeData(scene, runId, data = {}) {
        const source = foundry.utils.deepClone(data || {});
        const events = (Array.isArray(source.events) ? source.events : []).map(event => {
            const { message: _discardedMessage, ...eventData } = event || {};
            return {
                ...eventData,
                scope: ["personal", "local", "regional"].includes(String(event?.scope || ""))
                    ? String(event.scope)
                    : "regional",
                narrative: ChronicleNarrativeModel.normalize(event?.narrative)
            };
        });
        const years = Number(source.years || source.summary?.years || 0);
        return {
            schemaVersion: SCHEMA_VERSION,
            title: String(source.title || "Regional Chronicle"),
            theme: String(source.theme || "medieval"),
            sourceModuleId: String(source.sourceModuleId || ""),
            sourceProviderId: String(source.sourceProviderId || ""),
            sceneId: String(scene?.id || source.sceneId || ""),
            sceneName: String(scene?.name || source.sceneName || "Unnamed Region"),
            runId: String(runId || source.runId || ""),
            seed: String(source.seed || ""),
            years,
            partial: source.partial === true,
            summary: foundry.utils.deepClone(source.summary || {}),
            events
        };
    }
}
