import Advsf from "./character/advsf.mjs"
import Combat from "./character/combat.mjs"
import Effects from "./character/effects.mjs"
import Equipment from "./character/equipment.mjs"
import Liturgies from "./character/liturgies.mjs"
import Meta from "./character/meta.mjs"
import Skills from "./character/skills.mjs"
import Social from "./character/social.mjs";
import Spells from "./character/spells.mjs"

const {HandlebarsApplicationMixin} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets
const {ContextMenu} = foundry.applications.ux


class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {

    /** @inheritDoc */
    static DEFAULT_OPTIONS = {
        position: {width: 1100, height: 640},
        classes: ['dsa41', 'sheet', 'actor', 'character'],
        tag: 'form',
        form: {
            submitOnChange: true,
            closeOnSubmit: false,
            handler: CharacterSheet.#onSubmitForm
        },
        window: {
            resizable: true,
        },
        actions: {
            rollCombatSkill: CharacterSheet.#rollCombatSkill,
            rollSkill: CharacterSheet.#rollSkill,
            roll: CharacterSheet.#dieRoll,
            editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage,
            openEmbeddedDocument: CharacterSheet.#openEmbeddedDocument,
            openCultureDocument: CharacterSheet.#openCultureDocument,
            openSpeciesDocument: CharacterSheet.#openSpeciesDocument,

        }
    }

    static TABS = {
        sheet: {
            tabs: [],
            initial: 'meta'
        }
    }

    /** @inheritDoc */
    static PARTS = {
        form: {
            template: `systems/DSA_4-1/templates/actor/character/main-sheet.hbs`
        },
        meta: {
            template: Meta.template
        },
        social: {
            template: Social.template
        },
        advsf: {
            template: Advsf.template
        },
        combat: {
            template: Combat.template
        },
        equipment: {
            template: Equipment.template
        },
        skills: {
            template: Skills.template
        },
        spells: {
            template: Spells.template
        },
        liturgies: {
            template: Liturgies.template
        },
        effects: {
            template: Effects.template
        }
    }


    /**
     *
     * @param {PointerEvent} event
     */
    static #rollSkill(event) {
        const {id} = event.target.dataset
        const skill = this.document.items.get(id)
        if (skill?.system?.roll) {
            skill.system.roll("publicroll")
        }
    }

    /**
     *
     * @param {PointerEvent} event
     */
    static #rollCombatSkill(event) {
        const {id} = event.target.dataset
        const skill = this.document.items.get(id)
        if (skill?.system?.roll) {
            skill.system.roll("publicroll", event.shiftKey ? "PARRY" : "ATTACK")
        }
    }

    static #dieRoll(event) {
        event.preventDefault()
        const dataset = event.currentTarget.dataset
        if (dataset.roll) {
            let label = dataset.label ? `[Attribut] ${dataset.label}` : ''
            let roll = new Roll(dataset.roll, this.actor.getRollData())
            roll.toMessage({
                speaker: ChatMessage.getSpeaker({actor: this.actor}),
                flavor: label,
                rollMode: game.settings.get('core', 'rollMode'),
            });
            return roll
        }
    }

    /**
     *
     * @param {MouseEvent} event
     */
    static #openEmbeddedDocument(event) {
        let dataset = event.target.dataset
        if (!dataset.itemId && !dataset.id) {
            dataset = event.target.parentElement.dataset
        }
        const id = dataset.itemId ?? dataset.id

        this.document.items.get(id).sheet.render(true)
    }

    static #openCultureDocument() {
        this.document.itemTypes["Culture"]?.[0]?.sheet.render(true)
    }

    static #openSpeciesDocument() {
        this.document.itemTypes["Species"]?.[0]?.sheet.render(true)
    }

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

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


        _getTabsConfig(group) {
            const tabs = foundry.utils.deepClone(super._getTabsConfig(group))
            Meta._getTabConfig(tabs, this);
            Social._getTabConfig(tabs, this);
            Advsf._getTabConfig(tabs, this)
            Combat._getTabConfig(tabs, this)
            Equipment._getTabConfig(tabs, this)
            Skills._getTabConfig(tabs, this)
            Spells._getTabConfig(tabs, this)
            Liturgies._getTabConfig(tabs, this)
            Effects._getTabConfig(tabs, this)
            return tabs
        }

    async _preparePartContext(partId, context) {
        switch (partId) {
            case "form":


                const actorData = context.document
                context.system = actorData.system
                context.isOwner = actorData.isOwner
                context.flags = actorData.flags
                context.derived = context.document.system
                context.professions = actorData.items.filter(p => p.type === 'Profession').map(p => {
                    // is tarnidentitaet revealed?
                    if (p.system.revealed) {
                        return {
                            id: p.id,
                            name: p.name,
                            alias: p.system.alias,
                        }
                    } else {
                        return {
                            id: p.id,
                            name: p.system.alias ?? p.name,
                            alias: p.name,
                        }
                    }
                })

                context.spezies = ""
                if (actorData.itemTypes["Species"]?.[0]) {
                    const speciesData = actorData.itemTypes["Species"][0]
                    if (actorData.system.geschlecht === "männlich") {
                        context.spezies = speciesData.system.masculineDemonym
                    } else {
                        context.spezies = speciesData.system.feminineDemonym
                    }
                }

                context.kultur = ""
                if (actorData.itemTypes["Culture"]?.[0]) {
                    const cultureData = actorData.itemTypes["Culture"][0]
                    if (actorData.system.geschlecht === "männlich") {
                        context.kultur = cultureData.system.masculineDemonym
                    } else {
                        context.kultur = cultureData.system.feminineDemonym
                    }
                }

                context.originalName = actorData.name
                context.name = context.derived.name ?? actorData.name
                context.img = actorData.img
                context.effects = actorData.effects ?? []

                context.maxWounds = actorData.system.wunden.max ?? 3
                context.wounds = actorData.system.wunden.aktuell ?? 0
                context.woundsFilled = []
                for (let i = 1; i <= context.maxWounds; i++) {
                    context.woundsFilled[i] = i <= context.wounds
                }

                context.zonenruestung = game.settings.get("DSA_4-1", "optional_ruestungzonen")
                context.trefferzonen = game.settings.get("DSA_4-1", "optional_trefferzonen")
                context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer")
                context.colorfulDice = game.settings.get('DSA_4-1', 'optional_colorfuldice')


                context.inidice = actorData.system.ini.wuerfel
                context.inivalue = actorData.system.ini.aktuell
                context.inimod = actorData.system.ini.mod

                context.aupper = Math.min((actorData.system.aup.aktuell / actorData.system.aup.max) * 100, 100)
                context.lepper = Math.min((actorData.system.lep.aktuell / actorData.system.lep.max) * 100, 100)
                context.keper = Math.min((actorData.system.kap.aktuell / actorData.system.kap.max) * 100, 100)
                context.aspper = Math.min((actorData.system.asp.aktuell / actorData.system.asp.max) * 100, 100)
                context.lepcurrent = actorData.system.lep.aktuell ?? 0

                context.aupcurrent = actorData.system.aup.aktuell ?? 0

                const fernkampf = actorData.findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData)
                const links = actorData.findEquipmentOnSlot("links", actorData.system.setEquipped, actorData)
                const rechts = actorData.findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData)
                context.attacks = [];

                if (fernkampf) {
                    const fkitems = fernkampf.system.rangedSkills.map((skillInQuestion) => actorData.items.find(p => p.name === skillInQuestion))
                    fkitems.forEach(async skill => {
                        const obj = await skill
                        context.attacks.push({
                            name: obj.name,
                            using: fernkampf.name,
                            atroll: `1d20cs<${this.document.system.fk.aktuell + obj.system.at}`,
                            at: `${this.document.system.fk.aktuell + obj.system.at}`,
                            tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod
                            tp: `${fernkampf.system.rangedAttackDamage}`,
                            iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`,
                            ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`,
                        })
                    })
                }
                if (links) {
                    const meitems = []
                    links.system.meleeSkills.forEach((skillInQuestion) => {
                        const item = actorData.items.find(p => p.name === skillInQuestion)
                        if (item) {
                            meitems.push(item)
                        }
                    })
                    meitems.forEach(skill => {
                        const obj = skill
                        context.attacks.push({
                            name: obj.name,
                            using: links.name,
                            atroll: `1d20cs<${this.document.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M
                            at: `${this.document.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`,
                            paroll: `1d20cs<${this.document.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M
                            pa: `${this.document.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`,
                            tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod
                            tp: `${links.system.meleeAttackDamage}`,
                            iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`,
                            ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`,
                        })
                    })
                }
                if (rechts) {
                    const meitems = []
                    rechts.system.meleeSkills.forEach((skillInQuestion) => {
                        const item = actorData.items.find(p => p.name === skillInQuestion)
                        if (item) {
                            meitems.push(item)
                        }
                    })
                    meitems.forEach(skill => {
                        const obj = skill
                        context.attacks.push({
                            name: obj.name,
                            using: rechts.name,
                            atroll: `1d20cs<${this.document.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`,  // TODO consider adding W/M
                            at: `${this.document.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`,
                            paroll: `1d20cs<${this.document.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`,  // TODO consider adding W/M
                            pa: `${this.document.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`,
                            tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod
                            tp: `${rechts.system.meleeAttackDamage}`,
                            iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
                            ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
                        })
                    })
                }

                context.attributes = [
                    {
                        eigenschaft: "mu",
                        name: "MU",
                        tooltip: "Mut",
                        wert: context.derived.attribute.mu.aktuell ?? 0,
                    },
                    {
                        eigenschaft: "kl",
                        name: "KL",
                        tooltip: "Klugheit",
                        wert: context.derived.attribute.kl.aktuell ?? 0,
                    },
                    {
                        eigenschaft: "in",
                        name: "IN",
                        tooltip: "Intuition",
                        wert: context.derived.attribute.in.aktuell ?? 0,
                    },
                    {
                        eigenschaft: "ch",
                        name: "CH",
                        tooltip: "Charisma",
                        wert: context.derived.attribute.ch.aktuell ?? 0,
                    },
                    {
                        eigenschaft: "ff",
                        name: "FF",
                        tooltip: "Fingerfertigkeit",
                        wert: context.derived.attribute.ff.aktuell ?? 0,
                    },
                    {
                        eigenschaft: "ge",
                        name: "GE",
                        tooltip: "Geschicklichkeit",
                        wert: context.derived.attribute.ge.aktuell ?? 0,
                    },
                    {
                        eigenschaft: "ko",
                        name: "KO",
                        tooltip: "Konstitution",
                        wert: context.derived.attribute.ko.aktuell ?? 0,
                    },
                    {
                        eigenschaft: "kk",
                        name: "KK",
                        tooltip: "Körperkraft",
                        wert: context.derived.attribute.kk.aktuell ?? 0,
                    },
                ]

                break;
            case "meta":
                await Meta._prepareContext(context, this.document)
                break
            case "social":
                await Social._prepareContext(context, this.document)
                break
            case "advsf":
                await Advsf._prepareContext(context, this.document)
                break
            case "combat":
                await Combat._prepareContext(context, this.document)
                break
            case "equipment":
                await Equipment._prepareContext(context, this.document)
                break
            case "skills":
                await Skills._prepareContext(context, this.document)
                break
            case "spells":
                await Spells._prepareContext(context, this.document)
                break
            case "liturgies":
                await Liturgies._prepareContext(context, this.document)
                break
            case "effects":
                await Effects._prepareContext(context, this.document)
                break
        }
        return context
    }

    _onRender(context, options) {
        Meta._onRender(context, options, this.element)
        Social._onRender(context, options, this.element)
        Advsf._onRender(context, options, this)
        Combat._onRender(context, options, this.element)
        Effects._onRender(context, options, this.element)
        Equipment._onRender(context, options, this)
        Liturgies._onRender(context, options, this.element)
        Skills._onRender(context, options, this.element)
        Spells._onRender(context, options, this.element)
    }

    async _canDragDrop() {
        return true
    }


    // 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);

            if (document.type === "Equipment" || document.type === "Advantage" || document.type === "Spell" || document.type === "Liturgy" || document.type === "ActiveEffect" || document.type === "SpecialAbility") {
                // No duplication by moving items from one actor to another
                if (document.parent && document.parent !== this.actor) {
                    document.parent.items.get(document._id).delete()
                }

                await this._onDropDocument(event, document);
            }
        }
    }

}

export default CharacterSheet
