import Advsf from "./character/advsf.mjs"
import Health from "./character/health.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"
import {CombatActionDialog} from "../dialog/combatAction.mjs";
import {ActionManager} from "./actions/action-manager.mjs";
import {DefenseActionDialog} from "../dialog/defenseAction.mjs";
import {RestingDialog} from "../dialog/restingDialog.mjs";
import {LiturgyDialog} from "../dialog/liturgyDialog.mjs";
import {TalentDialog} from "../dialog/talentDialog.mjs";
import {AttributeDialog} from "../dialog/attributeDialog.mjs";
import {ItemBrowserDialog} from "../dialog/itemBrowserDialog.mjs";
import * as EquipmentDocument from "../documents/equipment.mjs";
import {StandaloneADVSF} from "./character-standalone/advsf.mjs";
import {StandaloneSkills} from "./character-standalone/skills.mjs";
import {Bagpack} from "./character-standalone/bagpack.mjs";
import {StandaloneSpells} from "./character-standalone/spells.mjs";
import {StandaloneLiturgies} from "./character-standalone/liturgies.mjs";
import {StandaloneHealth} from "./character-standalone/health.mjs";
import {SpellDialog} from "../dialog/spellDialog.mjs";
import {displayRoll} from "../globals/displayRoll.js";
import {ResourceType} from "../data/character.mjs";
import {EditResourceDialog} from "../dialog/resourceDialog.mjs";
import {MeditatingDialog} from "../dialog/meditatingDialog.mjs";

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


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,
            rollFlaw: CharacterSheet.rollFlaw,
            rollAttribute: CharacterSheet.#rollAttribute,
            editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage,
            openEmbeddedDocument: CharacterSheet.openEmbeddedDocument,
            openCultureDocument: CharacterSheet.#openCultureDocument,
            openSpeciesDocument: CharacterSheet.#openSpeciesDocument,
            openCombatAction: CharacterSheet.#openCombatAction,
            openLiturgyDialog: CharacterSheet.openLiturgyDialog,
            openSpellDialog: CharacterSheet.openSpellDialog,
            openSkillDialog: CharacterSheet.openSkillDialog,
            castSpell: CharacterSheet.castSpell,
            progressCooldown: CharacterSheet.#progressCooldown,
            cancelCooldown: CharacterSheet.#cancelCooldown,
            activateCooldown: CharacterSheet.#activateCooldown,
            rest: CharacterSheet.#startResting,
            meditate: CharacterSheet.#startMeditating,
            removeEffect: CharacterSheet.#removeEffect,
            rollDamage: CharacterSheet.#rollDamage,
            openItemBrowser: CharacterSheet.openItemBrowser,
            newItem: CharacterSheet.addNewItem,
            toggleFav: CharacterSheet.toggleFav,
            openStandaloneADVSF: CharacterSheet.#openStandaloneADVSF,
            openStandaloneSkills: CharacterSheet.#openStandaloneSkills,
            openBagpack: CharacterSheet.#openBagpack,
            openStandaloneSpells: CharacterSheet.#openStandaloneSpells,
            openStandaloneLiturgies: CharacterSheet.#openStandaloneLiturgies,
            openStandaloneHealth: CharacterSheet.#openStandaloneHealth,
            setWounds: CharacterSheet.#setWounds,
            switchSet: CharacterSheet.#switchSet,
            openInitiative: CharacterSheet.#openInitiative,
            editLep: CharacterSheet.#editLep,
            editAup: CharacterSheet.#editAup,
            editAsp: CharacterSheet.#editAsp,
            editKap: CharacterSheet.#editKap,
        }
    }

    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
        },
        health: {
            template: Health.template
        },
        equipment: {
            template: Equipment.template,
            scrollable: ['.inventory']
        },
        skills: {
            template: Skills.template,
            scrollable: ['.tab.skills']
        },
        spells: {
            template: Spells.template
        },
        liturgies: {
            template: Liturgies.template
        },
        effects: {
            template: Effects.template
        },
    }


    /**
     *
     * @param {PointerEvent} event
     */
    static #rollSkill(event) {
        const {id} = event.target.dataset

        new TalentDialog(this.document, id).render(true)
    }

    /**
     *
     * @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 #rollAttribute(event, target) {

        new AttributeDialog(this.document, {
            name: target.dataset.name,
            value: target.dataset.value,
            symbol: target.dataset.symbol,
        }).render(true)
    }

    static async rollFlaw(event, target) {
        new AttributeDialog(this.document, target.dataset.itemId).render(true)
    }

    // TODO: add combat statistics and dialog
    static async #openInitiative(event, target) {
        const {formula} = target.dataset
        const evaluated = await new Roll(formula.replace("w", "d")).evaluate()
        const context = {
            formula,
            initiativeRolled: evaluated.terms[0].results[0].result,
            total: evaluated.total
        }
        await displayRoll(evaluated, game.user, this.document, false, false, 'systems/DSA_4-1/templates/chat/initiative-message.hbs', context)
    }

    static async #progressCooldown(event, target) {
        const {cooldownId} = target.dataset
        const cooldowns = this.document.system.cooldowns
        const cooldown = this.document.system.cooldowns[cooldownId]
        cooldowns.splice(cooldownId, 1)

        if (cooldown) {
            cooldown.current = cooldown.current + 1
        }

        cooldowns.push(cooldown)
        this.document.update({"system.cooldowns": cooldowns.sort((a, b) => a.current - b.current)})
        ui.notifications.info(`Abklingzeit von ${cooldown.data.title} um 1 Aktion reduziert`)
    }

    static async #cancelCooldown(event, target) {
        const {cooldownId} = target.dataset
        const cooldown = this.document.system.cooldowns[cooldownId]
        const cooldowns = this.document.system.cooldowns

        cooldowns.splice(cooldownId, 1)

        this.document.update({"system.cooldowns": cooldowns.sort((a, b) => a.current - b.current)})
        ui.notifications.info(`${cooldown.data.maneuver.name} abgebrochen`)
    }

    static async #activateCooldown(event, target) {
        const {cooldownId} = target.dataset
        const cooldowns = this.document.system.cooldowns
        const cooldown = this.document.system.cooldowns[cooldownId]

        if (cooldown && cooldown.current >= cooldown.start) {
            const am = new ActionManager(this.document)
            const action = new Function(`return ${cooldown.data.maneuver}`)

            if (action) {
                action()(this.document.system.cooldowns, {...cooldown.data, actor: this.document})
            }
        }

        cooldowns.splice(cooldownId, 1)

        this.document.update({"system.cooldowns": cooldowns.sort((a, b) => a.current - b.current)})
        ui.notifications.info(`${cooldown.data.title} ausgeführt`)
    }

    /**
     *
     * @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)
    }

    static #openCombatAction(event, target) {
        let {weapon, skill} = target.dataset

        switch (target.dataset.mode) {
            case "attack":
                new CombatActionDialog(this.document, {weapon, skill}).render(true)
                break
            case "defense":
                new DefenseActionDialog(this.document, {weapon, skill}).render(true)
                break
        }
    }

    static openLiturgyDialog(event, target) {
        const {id, lkp, deity} = target.dataset
        new LiturgyDialog(this.document, lkp, id, deity).render(true)
    }

    static openSpellDialog(event, target) {
        const {itemId} = target.dataset
        this.document.itemTypes["Spell"]?.find(p => p.id === itemId)?.sheet.render(true)
    }

    static openSkillDialog(event, target) {
        const {itemId} = target.dataset
        this.document.itemTypes["Skill"]?.find(p => p.id === itemId)?.sheet.render(true)
    }

    static castSpell(event, target) {
        const {itemId} = target.dataset
        new SpellDialog(this.document, itemId).render(true)
    }

    static #editAup(event, target, isRightClicked) {

        if (!isRightClicked) {
            const min = 0
            const current = this.document.system.aup.aktuell
            const max = this.document.system.aup.max

            const dialog = new EditResourceDialog(this.document, ResourceType.AU, min, current, max)
            dialog.render(true)
            target.parentElement.querySelector('input').blur();
        }
    }

    static #editLep(event, target, isRightClicked) {

        if (!isRightClicked) {
            const min = 0
            const current = this.document.system.lep.aktuell
            const max = this.document.system.lep.max

            const dialog = new EditResourceDialog(this.document, ResourceType.LE, min, current, max)
            dialog.render(true)
            target.parentElement.querySelector('input').blur();
        }
    }

    static #editAsp(event, target, isRightClicked) {

        if (!isRightClicked) {
            const min = 0

            const current = this.document.system.asp.aktuell
            const max = this.document.system.asp.max

            const dialog = new EditResourceDialog(this.document, ResourceType.AE, min, current, max)
            dialog.render(true)
            target.parentElement.querySelector('input').blur();
        }
    }

    static #editKap(event, target, isRightClicked) {

        if (!isRightClicked) {
            const min = 0
            const current = this.document.system.kap.aktuell
            const max = this.document.system.kap.max

            const dialog = new EditResourceDialog(this.document, ResourceType.KE, min, current, max)
            dialog.render(true)
            target.parentElement.querySelector('input').blur();
        }
    }

    static #startResting(event, target) {

        const dialog = new RestingDialog(this.document)

        dialog.render(true)
    }

    static #startMeditating(event, target) {
        const dialog = new MeditatingDialog(this.document)
        dialog.render(true)
    }

    static async #removeEffect(event, target) {
        const {actorId, effectId} = target.dataset

        if (actorId === this.document._id) {

            const item = this.document.items.get(effectId)

            if (item.type === "ActiveEffect") {
                this.document.deleteEmbeddedDocuments("Item", [effectId])
            }

        }

    }

    static async openItemBrowser(event, target) {
        new ItemBrowserDialog(this.document).render(true)
    }

    static async addNewItem(event, target) {
        let item = new EquipmentDocument.Equipment({
            name: "Neuer Gegenstand",
            type: "Equipment",
        })
        const items = await this.document.createEmbeddedDocuments("Item", [item])
        items[0].sheet.render(true)
    }

    static async toggleFav(event, target) {
        const {itemId} = target.dataset
        const doc = this.document.items.find(p => p.id === itemId)

        if (doc) {
            const previous = doc.getFlag("DSA_4-1", "favourite") ?? false
            doc.setFlag("DSA_4-1", "favourite", !previous)
        }
    }

    static async #openStandaloneADVSF(event, target) {
        new StandaloneADVSF(this.document)
    }

    static async #openStandaloneHealth(event, target) {
        new StandaloneHealth(this.document)
    }

    static async #openStandaloneSkills(event, target) {
        new StandaloneSkills(this.document)
    }

    static async #openBagpack(event, target) {
        new Bagpack(this.document)
    }

    static async #openStandaloneSpells(event, target) {
        new StandaloneSpells(this.document)
    }

    static async #openStandaloneLiturgies(event, target) {
        new StandaloneLiturgies(this.document)
    }

    static async #setWounds(event, target) {
        const {value} = target.dataset
        this.document.update({"system.wunden.aktuell": value})
        this.render(true)
    }

    static async #switchSet(event, target) {
        const {id} = target.dataset
        this.document.update({"system.setEquipped": id})
        this.render(true)
    }

    _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["system.lep.aktuell"]?.[1]) {
            formData.object["system.lep.aktuell"] = formData.object["system.lep.aktuell"][0]
        }

        if (formData.object["system.aup.aktuell"]?.[1]) {
            formData.object["system.aup.aktuell"] = formData.object["system.aup.aktuell"][0]
        }

        if (formData.object["system.asp.aktuell"]?.[1]) {
            formData.object["system.asp.aktuell"] = formData.object["system.asp.aktuell"][0]
        }

        if (formData.object["system.kap.aktuell"]?.[1]) {
            formData.object["system.kap.aktuell"] = formData.object["system.kap.aktuell"][0]
        }

        await this.document.update(formData.object)

        return false
    }

    static async #rollDamage(event, target) {
        let {weapon, isRanged} = target.dataset
        isRanged = isRanged == "true"
        weapon = this.document.items.get(weapon)
        if (weapon) {
            const damageFormula = isRanged ? weapon.system.rangedAttackDamage : weapon.system.meleeAttackDamage
            const calculation = await foundry.applications.api.DialogV2.prompt({
                window: {title: game.i18n.format("COMBAT_DIALOG_TP.windowTitle")},
                content: `<div><label><span>${game.i18n.format("COMBAT_DIALOG_TP.regularFormula")}</span><input type="text" name="formula" value="${damageFormula}"></label></div><div><label><span>${game.i18n.format("COMBAT_DIALOG_TP.bonusDamage")}</span><input type="text" name="bonusDamage" value="0"></label></div>`,
                ok: {
                    label: game.i18n.format("COMBAT_DIALOG_TP.buttonText"),
                    callback: (event, button, dialog) => {
                        return {
                            formula: button.form.elements.formula.value,
                            bonusDamage: button.form.elements.bonusDamage.value
                        }
                    }
                }
            });

            const sanitisedFormula = calculation.formula.replace(/wW/g, "d")
            const suffix = calculation.bonusDamage >= 0 ? "+" + calculation.bonusDamage : calculation.bonusDamage

            let r = new Roll(sanitisedFormula + suffix, this.document.getRollData());
            const label = `Schadenswurf`
            await r.toMessage({
                speaker: ChatMessage.getSpeaker({actor: this.document}),
                flavor: label,
                rollMode: game.settings.get('core', 'rollMode'),
            })
        }
    }


    _getTabsConfig(group) {
        const tabs = foundry.utils.deepClone(super._getTabsConfig(group))
        Meta._getTabConfig(tabs, this)
        Social._getTabConfig(tabs, this)
        Advsf._getTabConfig(tabs, this)
        Health._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.actorId = actorData._id
                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.meta.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.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
                context.aspcurrent = actorData.system.asp.aktuell ?? 0
                context.kapcurrent = actorData.system.kap.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(skill => {
                        if (skill) {
                            context.attacks.push({
                                name: skill.name,
                                id: fernkampf._id,
                                skillId: skill._id,
                                using: fernkampf.name,
                                isRanged: true,
                                at: `${this.document.system.fk.aktuell + skill.system.at}`,
                                tp: `${fernkampf.system.rangedAttackDamage}`,
                                ini: `${context.inidice}w6 + ${context.inivalue ?? 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,
                            id: links._id,
                            skillId: skill._id,
                            using: links.name,
                            isRanged: false,
                            at: `${this.document.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`,
                            pa: `${this.document.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`,
                            tp: `${links.system.meleeAttackDamage}`,
                            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,
                            id: rechts._id,
                            skillId: skill._id,
                            using: rechts.name,
                            isRanged: false,
                            at: `${this.document.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`,
                            pa: `${this.document.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`,
                            tp: `${rechts.system.meleeAttackDamage}`,
                            ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
                        })
                    })
                }

                context.favourites = actorData.items.filter(item => item.getFlag("DSA_4-1", "favourite") === true).map(item => {
                    let id = item.id
                    let t = null
                    switch (item.type) {
                        case "Spell":
                            t = "systems/DSA_4-1/templates/ui/partial-mini-rollable-spell-button.hbs"
                            break;
                        case "Skill":
                            switch (item.system.gruppe) {
                                case "Kampf":
                                    t = "systems/DSA_4-1/templates/ui/partial-mini-rollable-weaponskill-button.hbs"
                                    break;
                                case "Sprachen":
                                    t = "systems/DSA_4-1/templates/ui/partial-mini-rollable-language-button.hbs"
                                    break;
                                default:
                                    t = "systems/DSA_4-1/templates/ui/partial-mini-rollable-button.hbs"
                            }
                            break;
                        case "Liturgy":
                            t = "systems/DSA_4-1/templates/ui/partial-mini-rollable-liturgy-button.hbs"
                            break;
                        default:
                            t = null
                    }

                    let obj = Object.assign({}, item)

                    obj.fav = item.getFlag("DSA_4-1", "favourite")
                    obj.id = id
                    obj.group = item.system.gruppe ?? null

                    if (t) {
                        obj.template = t
                    }

                    return obj
                })

                context.cooldowns = actorData.system.cooldowns ?? []
                context.cooldowns.forEach(cooldown => {
                    let weapon = null
                    let target = null
                    let tooltip = cooldown.data.title
                    if (cooldown.data.weapon) {
                        weapon = this.document.itemTypes["Equipment"].find(p => p._id === cooldown.data.weapon)
                        tooltip += `<br/>Waffe: ${weapon.name}`
                    }
                    if (cooldown.data.target && game.scenes.current.tokens.length > 0) {
                        target = game.actors.get(game.scenes.current.tokens.find(p => p._id === cooldown.data.target).actorId)
                        tooltip += `<br/>Ziel: ${target.name}`
                    }
                    cooldown.title = cooldown.data.title
                    cooldown.progress = ((cooldown.current / cooldown.start) * 100) + "%"
                    if (cooldown.start - cooldown.current > 0) {
                        cooldown.tooltip = tooltip + `<br/>Aktionen verbleibend: ${cooldown.start - cooldown.current}<hr/><i class="fa-solid fa-computer-mouse"></i>: 1 Aktion aufwenden`
                    } else {
                        cooldown.tooltip = tooltip + `<br/>Aktionen verbleibend: ${cooldown.start - cooldown.current}<hr/><i class="fa-solid fa-computer-mouse"></i>: Aktion durchführen`
                    }

                })

                context.hasSpells = actorData.itemTypes["Spell"].length > 0
                context.hasLiturgies = actorData.itemTypes["Liturgy"].length > 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: "Gewandtheit",
                        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 "health":
                await Health._prepareContext(context, this.document)
                break
            case "equipment":
                await Equipment._prepareContext(context, this.document, this)
                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
    }

    _onPosition(position) {

        if (position.width < 300) {
            this.element.classList.add("tiny")
            this.element.querySelector(".sidebuttons").style.left = (position.width + position.left) + "px"
            this.element.querySelector(".sidebuttons").style.top = (position.top) + "px"
        } else {
            this.element.classList.remove("tiny")
        }

    }

    _onRender(context, options) {
        Meta._onRender(context, options, this.element)
        Social._onRender(context, options, this.element)
        Advsf._onRender(context, options, this)
        Health._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)

        this._onPosition(this.position)
    }

    async _canDragDrop() {
        return true
    }

    async _onDrop(event) {
        const data = TextEditor.implementation.getDragEventData(event)
        const targetDocument = this.actor.itemTypes["Equipment"].find(p => p._id === event.target.dataset['itemId'])

        if (event.target.dataset["target"] && event.target.dataset["setId"]) {

            const documentClass = foundry.utils.getDocumentClass(data.type)
            if (documentClass) {
                const document = await documentClass.fromDropData(data)

                const {setId, target} = event.target.dataset
                const updateObject = this.actor.getEquipmentSetUpdateObject()
                updateObject[`system.heldenausruestung.${setId}.${target}`] = document.id
                await this.actor.update(updateObject)
            }
            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" || document.type === "Skill") {
                // No duplication by moving items from one actor to another

                if ((targetDocument?.name ?? false) === document.name && targetDocument._id !== document._id && await foundry.applications.api.DialogV2.confirm({
                    content: `<span>Gegenstände der Art <strong>${document.name}</strong> (Neue Anzahl: ${targetDocument.system.quantity + document.system.quantity}) zusammenlegen?</span>`,
                    rejectClose: false,
                    modal: true,
                    window: {
                        title: `Gegenstände zusammenlegen`
                    }
                })) {
                    // combine
                    await targetDocument.update({"system.quantity": targetDocument.system.quantity + document.system.quantity})
                    await this.actor.deleteEmbeddedDocuments('Item', [document._id])
                    return false
                } else {

                    if (document.parent && document.parent !== this.actor) {
                        game.DSA41.socket.executeAsGM("removeFromLootTable", document.parent.id, document._id)
                    }

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

    async _postRender() {
        this.element.querySelectorAll('.sidebar-element.resource-bar[data-action]').forEach( e => {
            const { action} = e.dataset;
            e.addEventListener('contextmenu', (event) => {
                if (CharacterSheet.DEFAULT_OPTIONS.actions[action]) {
                    CharacterSheet.DEFAULT_OPTIONS.actions[action].bind(this)(event, event.target, true);
                }
            })
        })
    }

}

export default CharacterSheet
