const {HandlebarsApplicationMixin, DocumentSheetV2} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets

export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) {

    /** @inheritDoc */
    static DEFAULT_OPTIONS = {
        position: {width: 520, height: 480},
        classes: ['dsa41', 'sheet', 'actor', 'group'],
        tag: 'form',
        dragDrop: [{
            dropSelector: '.tab.inventory.active'
        }],
        form: {
            submitOnChange: true,
            closeOnSubmit: false,
            handler: GroupSheet.#onSubmitForm
        },
        window: {
            resizable: true,
        },
        actions: {
            roll: GroupSheet.#dieRoll,
            editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage,
            openEmbeddedDocument: GroupSheet.#openEmbeddedDocument,
            openActorDocument: GroupSheet.#openActorDocument,
        }
    }

    static TABS = {
        sheet: {
            tabs: [
                {id: 'members', group: 'sheet', label: 'Gruppenmitglieder'},
                {id: 'inventory', group: 'sheet', label: 'Gruppeninventar'},
            ],
            initial: 'members'
        }
    }

    /** @inheritDoc */
    static PARTS = {
        form: {
            template: `systems/DSA_4-1/templates/actor/group/main-sheet.hbs`
        },
        members: {
            template: `systems/DSA_4-1/templates/actor/group/tab-members.hbs`
        },
        inventory: {
            template: `systems/DSA_4-1/templates/actor/group/tab-inventory.hbs`
        },
        settings: {
            template: `systems/DSA_4-1/templates/actor/group/tab-settings.hbs`
        }
    }

    constructor(options = {}) {
        super(options);
    }

    _configureRenderOptions(options) {
        super._configureRenderOptions(options)

        if (options.window) {
            options.window.title = this.document.name
        }

        return options
    }

    /**
     * Handle form submission
     * @this {AdvantageSheet}
     * @param {SubmitEvent} event
     * @param {HTMLFormElement} form
     * @param {FormDataExtended} formData
     */
    static async #onSubmitForm(event, form, formData) {
        event.preventDefault()

        if (formData.object.name) {
            await (game.folders.get(this.document.system.groupId)).update({name: formData.object.name})
        }

        await this.document.update(formData.object) // Note: formData.object
    }

    #stringToKeyFieldName(s) {
        return s
    }


    static #openEmbeddedDocument(event) {
        const dataset = event.target.parentElement.dataset
        const id = dataset.itemId ?? dataset.id
        this.document.items.get(id).sheet.render(true)
    }


    static async #openActorDocument(event) {
        const dataset = event.target.parentElement.dataset
        const id = dataset.itemId ?? dataset.id
        game.actors.get(id).sheet.render(true)
    }

    static async #dieRoll(evt) {
    }

    async #onUpdateCharacterSettings(data) {
        if (data.type === "Character") {

            // update group
            let settings = {...this.document.system.settings}
            data.items.filter((i) => i.type === "Advantage").forEach((advantage) => {
                if (!settings[this.#stringToKeyFieldName(advantage.name)]) {
                    settings[this.#stringToKeyFieldName(advantage.name)] = false
                }
            })
            data.items.filter((i) => i.type === "Skill").forEach((skill) => {
                if (!settings[this.#stringToKeyFieldName(skill.name)]) {
                    settings[this.#stringToKeyFieldName(skill.name)] = false
                }
            })

            await this.document.update({"system.settings": settings})
        }
    }

    _getTabsConfig(group) {
        const tabs = foundry.utils.deepClone(super._getTabsConfig(group))

        // Modify tabs based on document properties
        if (game.user.isGM) {
            tabs.tabs.push({id: "settings", group: "sheet", label: "Einstellungen"})
        }

        return tabs
    }

    /** @override */
    async _prepareContext(options) {
        const context = await super._prepareContext(options)
        const groupData = context.document
        context.system = groupData.system
        context.flags = groupData.flags
        context.characters = []
        context.isGM = game.user.isGM
        context.name = groupData.name
        context.img = groupData.img

        context.fields = [];

        const hiddenFields = Object.entries(groupData.system.settings)
            .sort(([key, value], [otherKey, otherValue]) => key.localeCompare(otherKey))
            .filter(([key, value]) => value === true)
            .map(([key, value]) => key)

        context.fields = {}
        context.fields["head"] = {}
        for (const field of hiddenFields) {

            context.fields[field] = {}

            for (const characterId of groupData.system.characters) {
                const character = await game.actors.get(characterId)
                context.fields[field][character.name] = "-"

            }
        }

        // TODO hook on changes in the given folder
        const characters = await game.folders.get(groupData.system.groupId).contents

        for (const character of characters) {

            character.items.filter((i) => i.type === "Advantage").filter((i) => hiddenFields.includes(this.#stringToKeyFieldName(i.name))).map((advantage) => {
                const n = this.#stringToKeyFieldName(advantage.name)
                if (!context.fields[n]) {
                    context.fields[n] = {}
                }
                context.fields[n][character.name] = advantage.system.value ?? "Ja" // TODO: Allow GM roll
            })

            character.items.filter((i) => i.type === "Skill").filter((i) => hiddenFields.includes(this.#stringToKeyFieldName(i.name))).map((skill) => {
                const n = this.#stringToKeyFieldName(skill.name)
                if (!context.fields[n]) {
                    context.fields[n] = {}
                }
                context.fields[n][character.name] = {
                        taw: skill.system.taw ?? "0",
                        name: skill.name,
                        actor: character._id,
                    }
                    ?? 0
            })

            context.fields.head[character.name] =
                {
                    img: character.img,
                    name: character.name,
                    id: character._id,
                    attributes: [
                        {name: "MU", value: character.system.attribute.mu.aktuell},
                        {name: "KL", value: character.system.attribute.kl.aktuell},
                        {name: "IN", value: character.system.attribute.in.aktuell},
                        {name: "CH", value: character.system.attribute.ch.aktuell},
                        {name: "FF", value: character.system.attribute.ff.aktuell},
                        {name: "GE", value: character.system.attribute.ge.aktuell},
                        {name: "KO", value: character.system.attribute.ko.aktuell},
                        {name: "KK", value: character.system.attribute.kk.aktuell},
                    ],
                    isLimited: character.isOwner || !character.limited,
                    isVisible: character.isOwner || character.visible,
                    isOwner: character.isOwner
                }
        }

        context.inventoryItems = [];
        const actorData = context.document;
        actorData.items.forEach((item, index) => {
            if (item.type === "Equipment") {
                context.inventoryItems.push({
                    index: index,
                    id: item._id,
                    quantity: item.system.quantity,
                    name: item.name,
                    icon: item.img
                })
            }
        })

        context.settings = Object.fromEntries(Object.entries(groupData.system.settings)
            .sort(([key, value], [otherKey, otherValue]) => key.localeCompare(otherKey)))

        return await context;
    }

    _onRender(context, options) {
        /*ContextMenu.implementation.create(this, this.element, ".equipment", [
            {
                name: "Aus dem Gruppeninventar entfernen",
                icon: '<i class="fa-solid fa-trash"></i>',
                callback: (event) => {
                    this.object.deleteEmbeddedDocuments('Item', [event[0].dataset.id])
                },
                condition: () => true
            }
        ], {
            jQuery: false
        });*/

        // Drag-drop
        new foundry.applications.ux.DragDrop.implementation({
            dragSelector: ".inventory-table .equipment",
            dropSelector: ".inventory",
            permissions: {
                dragstart: this._canDragStart.bind(this),
                drop: this._canDragDrop.bind(this)
            },
            callbacks: {
                dragstart: this._onDragStart.bind(this),
                drop: this._onDrop.bind(this)
            }
        }).bind(this.element);

        // Update Group Members when either an Actor was moved into the linked Folder or removed from the linked Folder
        Hooks.on('updateActor', (data) => {
            if (data._id !== this.document._id) { // dont update yourself when you update yourself... baka!
                if (data.type === "Character" && data.folder?._id === this.document.system.groupId) {
                    this.#onUpdateCharacterSettings(data)
                    this.render()
                } else if (data.type === "Character") {
                    this.render()
                }
            }
        });

    }

    /**
     * An event that occurs when a drag workflow begins for a draggable item on the sheet.
     * @param {DragEvent} event       The initiating drag start event
     * @returns {Promise<void>}
     * @protected
     */
    async _onDragStart(event) {
        const target = event.currentTarget;
        if ("link" in event.target.dataset) return;
        let dragData;

        // Owned Items
        if (target.dataset.itemId) {
            const item = this.actor.items.get(target.dataset.itemId);
            dragData = item.toDragData();
        }

        // Active Effect
        if (target.dataset.effectId) {
            const effect = this.actor.effects.get(target.dataset.effectId);
            dragData = effect.toDragData();
        }

        // Set data transfer
        if (!dragData) return;
        event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
    }

    // TODO needs to be fixed once Character Sheet is migrated to ActorSheetV2
    async _onDrop(event) {
        const data = TextEditor.implementation.getDragEventData(event);
        const actor = this.actor;
        const allowed = Hooks.call("dropActorSheetData", actor, this, data);
        if (allowed === false) return;

        // Dropped Documents
        const documentClass = foundry.utils.getDocumentClass(data.type);
        if (documentClass) {
            const document = await documentClass.fromDropData(data);
            await this._onDropDocument(event, document);

            // No duplication by moving items from one actor to another
            if (document.parent) {
                document.parent.items.get(document._id).delete()
            }
        }
    }

}
