import { getLocation, getLocationGeneratorProfileOptions, updateLocation } from "../../../api/locations.js";
import { promptTextInput } from "../../../api/ui.js";
import { SiteIconPicker } from "../../site/applications/SiteIconPicker.js";
import { SitePanel } from "../../site/applications/SitePanel.js";
import { LocationEntityModel } from "../models/LocationEntityModel.js";
import { LocationParentReference } from "../models/LocationParentReference.js";
import { PlaceParentService } from "../../places/services/PlaceParentService.js";
import { LocationEditorSectionRegistry } from "../services/LocationEditorSectionRegistry.js";

const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
const THREAD_FIELDS = [
    { key: "state", label: "State", help: "The location's present condition." },
    { key: "pressure", label: "Pressure", help: "What is currently affecting it." },
    { key: "opportunity", label: "Opportunity", help: "What could be gained here." },
    { key: "secret", label: "Secret", help: "What remains concealed." }
];

export class LocationDataEditor extends HandlebarsApplicationMixin(ApplicationV2) {
    #locationId = "";
    #candidate = null;
    #onSave = null;

    static DEFAULT_OPTIONS = {
        id: "augur-nexus-location-data-editor",
        classes: ["augur-nexus", "augur-theme-fantasy", "npc-data-editor", "location-data-editor"],
        tag: "div",
        window: { title: "Edit Location", resizable: true, minimizable: true },
        position: { width: 520, height: 700 },
        actions: {
            save: LocationDataEditor._onSave,
            closeEditor: LocationDataEditor._onClose,
            renameLocation: LocationDataEditor._onRenameLocation,
            changeLocationIcon: LocationDataEditor._onChangeLocationIcon,
            addProfileField: LocationDataEditor._onAddProfileField,
            deleteProfileField: LocationDataEditor._onDeleteProfileField,
            moveProfileFieldUp: LocationDataEditor._onMoveProfileFieldUp,
            moveProfileFieldDown: LocationDataEditor._onMoveProfileFieldDown
        }
    };

    static PARTS = { content: { template: "modules/augur-nexus/templates/campaign-entities/location-data-editor.hbs" } };

    static show({ locationId = "", candidate = null, onSave = null } = {}) {
        if (!game.user.isGM || (!locationId && !candidate)) return null;
        const app = new this({ locationId, candidate, onSave });
        app.render(true, { focus: true });
        return app;
    }

    constructor({ locationId = "", candidate = null, onSave = null } = {}, options = {}) {
        super(options);
        this.#locationId = locationId;
        this.#candidate = candidate ? foundry.utils.deepClone(candidate) : null;
        this.#onSave = typeof onSave === "function" ? onSave : null;
    }

    async _prepareContext() {
        const entity = this.#entity;
        const parentKey = LocationParentReference.toNodeKey(entity?.hierarchy?.parent);
        const profileOptions = await getLocationGeneratorProfileOptions(entity?.generation?.generatorId || "", {
            templateId: entity?.generation?.templateId || ""
        });
        return {
            missing: !entity,
            location: entity ? {
                id: entity.id,
                name: LocationEntityModel.getName(entity),
                subtitle: LocationEntityModel.getSubtitle(entity),
                imageSrc: LocationEntityModel.getThumbnail(entity)
            } : { name: "Missing Location" },
            profileFields: LocationEntityModel.getProfileFields(entity).map(field => ({
                ...field,
                multiline: field.type === "multiline"
            })),
            currentThreadFields: THREAD_FIELDS.map(field => ({
                ...field,
                value: String(entity?.currentThread?.[field.key] || ""),
                options: this.#buildOptions(profileOptions.fields?.[field.key] || [])
            })),
            editorSections: await LocationEditorSectionRegistry.renderFor(entity, {
                candidate: !!this.#candidate
            }),
            isRootSelected: !parentKey,
            parentOptions: PlaceParentService.getParentOptions({
                childType: "location",
                childKey: entity?.id ? `location:${entity.id}` : null,
                selectedKey: parentKey
            })
        };
    }

    _onRender(context, options) {
        super._onRender(context, options);
        this.setPosition(this.#getCenteredPosition());
        this.element.querySelector("form")?.addEventListener("submit", event => {
            event.preventDefault();
            this.#save();
        });
    }

    static async _onSave() { return this.#save(); }
    static async _onClose() { return this.close(); }

    static async _onRenameLocation() {
        const entity = this.#entity;
        if (!entity) return;
        const name = await promptTextInput({
            title: "Rename Location",
            label: "Name",
            value: LocationEntityModel.getName(entity),
            confirmLabel: "Rename"
        });
        if (!name) return;
        const updated = this.#candidate
            ? this.#applyCandidatePatch(entity, { display: { name } })
            : await updateLocation(entity.id, { display: { name } });
        this.#onSave?.(updated);
        this.render({ parts: ["content"] });
    }

    static async _onChangeLocationIcon() { await this.#changeLocationIcon(); }

    static async _onAddProfileField() {
        const container = this.element.querySelector("[data-profile-fields]");
        if (!container) return;
        const id = `field.${foundry.utils.randomID()}`;
        const row = document.createElement("div");
        row.className = "npc-data-custom-field-row";
        row.dataset.profileFieldRow = id;
        row.innerHTML = this.#renderProfileFieldRow({ id, label: "", value: "", type: "text" });
        this.#wireProfileFieldRow(row);
        container.append(row);
        row.querySelector("[name='profileField.label']")?.focus();
    }

    static async _onDeleteProfileField(event, target) { target?.closest?.("[data-profile-field-row]")?.remove(); }
    static async _onMoveProfileFieldUp(event, target) { this.#moveField(target, -1); }
    static async _onMoveProfileFieldDown(event, target) { this.#moveField(target, 1); }

    async #save() {
        const entity = this.#entity;
        const form = this.element.querySelector("form");
        if (!entity || !form) return;
        const formData = new FormData(form);
        const basePatch = {
            profile: { fields: this.#collectProfileFields(form) },
            currentThread: this.#collectCurrentThread(form),
            hierarchy: {
                parent: LocationParentReference.fromNodeKey(formData.get("hierarchy.parentKey"))
            }
        };
        try {
            const transformed = await LocationEditorSectionRegistry.transformPatch(entity, formData, basePatch, {
                candidate: !!this.#candidate
            });
            const updated = this.#candidate
                ? this.#applyCandidatePatch(entity, transformed.patch)
                : await updateLocation(entity.id, transformed.patch, transformed.moduleId ? { moduleId: transformed.moduleId } : undefined);
            ui.notifications.info(this.#candidate ? "Location candidate updated." : "Location updated.");
            await this.#onSave?.(updated);
            await this.close();
        } catch (error) {
            console.error(error);
            ui.notifications.error(error?.message || "Failed to update location.");
        }
    }

    async #changeLocationIcon() {
        const entity = this.#entity;
        if (!entity) return;
        const icons = await SitePanel.getAllBuiltInIcons();
        const currentSrc = LocationEntityModel.getImage(entity);
        const currentIconId = icons.find(icon => icon.src === currentSrc)?.id || (currentSrc ? "custom" : null);
        new SiteIconPicker(icons, currentIconId, "landmark", selection => {
            const nextSrc = typeof selection === "object" && selection?.id === "custom"
                ? selection.src || ""
                : icons.find(icon => icon.id === selection)?.src || currentSrc;
            if (nextSrc) void this.#setLocationIcon(nextSrc);
        }, {
            currentCustomIconSrc: currentIconId === "custom" ? currentSrc : "",
            allBuiltInIcons: icons,
            showThemeIconsOnly: false,
            filterByRole: false
        }).render(true);
    }

    async #setLocationIcon(path) {
        const entity = this.#entity;
        if (!entity || !path) return;
        const updated = this.#candidate
            ? this.#applyCandidatePatch(entity, { display: { imageSrc: path, thumbnailSrc: "" } })
            : await updateLocation(entity.id, { display: { imageSrc: path, thumbnailSrc: "" } });
        this.#onSave?.(updated);
        this.render({ parts: ["content"] });
    }

    #applyCandidatePatch(entity, patch) {
        this.#candidate = foundry.utils.mergeObject(foundry.utils.deepClone(entity), patch, { inplace: false, recursive: true });
        return foundry.utils.deepClone(this.#candidate);
    }

    #collectProfileFields(form) {
        return [...form.querySelectorAll("[data-profile-field-row]")]
            .map(row => ({
                id: row.querySelector("[name='profileField.id']")?.value || row.dataset.profileFieldRow || "",
                label: row.querySelector("[name='profileField.label']")?.value || "",
                value: row.querySelector("[name='profileField.value']")?.value || "",
                type: row.querySelector("[name='profileField.type']")?.value === "multiline" ? "multiline" : "text"
            }))
            .filter(field => String(field.label || "").trim() || String(field.value || "").trim());
    }

    #collectCurrentThread(form) {
        const formData = new FormData(form);
        return Object.fromEntries(THREAD_FIELDS.map(field => [
            field.key,
            String(formData.get(`currentThread.${field.key}`) || "").trim()
        ]));
    }

    #buildOptions(options = []) {
        return [...new Set((Array.isArray(options) ? options : [])
            .map(option => String(option?.value || option?.label || option || "").trim())
            .filter(Boolean))];
    }

    #renderProfileFieldRow(field = {}) {
        const safe = value => foundry.utils.escapeHTML(String(value || ""));
        return `<input type="hidden" name="profileField.id" value="${safe(field.id)}"><input type="hidden" name="profileField.type" value="${safe(field.type || "text")}"><input type="text" name="profileField.label" value="${safe(field.label)}" placeholder="Field" autocomplete="off"><input type="text" name="profileField.value" value="${safe(field.value)}" placeholder="Value" autocomplete="off"><button type="button" class="npc-data-custom-field-move" data-action="moveProfileFieldUp" title="Move field up" aria-label="Move field up"><i class="fas fa-arrow-up"></i></button><button type="button" class="npc-data-custom-field-move" data-action="moveProfileFieldDown" title="Move field down" aria-label="Move field down"><i class="fas fa-arrow-down"></i></button><button type="button" class="npc-data-custom-field-delete" data-action="deleteProfileField" title="Delete field" aria-label="Delete field"><i class="fas fa-trash"></i></button>`;
    }

    #wireProfileFieldRow(row) {
        row.querySelector("[data-action='deleteProfileField']")?.addEventListener("click", event => {
            event.preventDefault();
            event.stopPropagation();
            row.remove();
        });
        row.querySelector("[data-action='moveProfileFieldUp']")?.addEventListener("click", event => {
            event.preventDefault();
            event.stopPropagation();
            this.#moveField(event.currentTarget, -1);
        });
        row.querySelector("[data-action='moveProfileFieldDown']")?.addEventListener("click", event => {
            event.preventDefault();
            event.stopPropagation();
            this.#moveField(event.currentTarget, 1);
        });
    }

    #moveField(target, direction) {
        const row = target?.closest?.("[data-profile-field-row]");
        if (!row) return;
        if (direction < 0 && row.previousElementSibling?.matches("[data-profile-field-row]")) row.previousElementSibling.before(row);
        if (direction > 0 && row.nextElementSibling?.matches("[data-profile-field-row]")) row.nextElementSibling.after(row);
    }

    #getCenteredPosition() {
        const width = Math.max(460, Math.min(560, window.innerWidth - 40));
        const height = Math.max(600, Math.min(760, window.innerHeight - 40));
        return {
            width,
            height,
            left: Math.max(20, Math.round((window.innerWidth - width) / 2)),
            top: Math.max(20, Math.round((window.innerHeight - height) / 2))
        };
    }

    get #entity() {
        return this.#candidate || getLocation(this.#locationId);
    }
}
