 import {ActionManager} from "../sheets/actions/action-manager.mjs";

const {
    ApplicationV2, 
    HandlebarsApplicationMixin
} = foundry.applications.api


/**
 * @typedef TokenDistance
 * @property {Number} x
 * @property {Number} y
 * @property {Number} d
 * @property {Token} token
 */

export class DefenseActionDialog extends HandlebarsApplicationMixin(ApplicationV2) {

    static DEFAULT_OPTIONS = {
        classes: ['dsa41', 'dialog', 'combat'],
        tag: "form",
        position: {
            width: 480,
            height: 640
        },
        window: {
            resizable: false,
        },
        form: {
            submitOnChange: false,
            closeOnSubmit: true,
            handler: DefenseActionDialog.#onSubmitForm
        },
        actions: {
            selectWeaponAndSkill: DefenseActionDialog.#onSelectWeaponAndSkill,
            selectManeuver: DefenseActionDialog.#onSelectManeuver,
            defend: DefenseActionDialog.#onDefend,
        }
    }

    static PARTS = {
        form: {
            template: 'systems/DSA_4-1/templates/dialog/defense-action.hbs',
        }
    }

    /**
     * @type {Actor}
     * @private
     */
    _actor = null

    constructor(actor, data, attackData) {
        super();
        /*this._attackData = attackData ?? {
            modToDefense: 0,
            attacker: null,
            weapon: null, // is important to note as weapons like Chain Weapons or Flails can ignore Shields
        }*/
        this._actor = actor
        this._skillId = data.skill ? data.skill : null
        this._weaponId = data.weapon ? data.weapon : null
        this._defenseManeuverId = null
        this._actionManager = new ActionManager(this._actor)
        //if (this._actor) {
        //    this._actor.prepareDerivedData()
        //}
    }


    static async #onSelectTarget(event, target) {
        const {targetId} = target.dataset
        this._targetId = this._targetId === targetId ? null : targetId
        this.render({parts: ["form"]})
    }

    static async #onSelectManeuver(event, target) {
        const {maneuverId} = target.dataset
        this._defenseManeuverId = this._defenseManeuverId === maneuverId ? null : maneuverId
        this.render({parts: ["form"]})
    }


    static async #onSelectWeaponAndSkill(event, target) {
        const {weaponId, skillId} = target.dataset
        this._weaponId = this._weaponId === weaponId ? null : weaponId
        this._skillId = this._skillId === skillId ? null : skillId
        this.render({parts: ["form"]})
    }

    static async #onSubmitForm(event, form, formData) {
        event.preventDefault()
        const attack = this._attackData
        const maneuver = this.#evaluateManeuvers().find(p => p.id === this._defenseManeuverId)
        this._actor.rollDefense({
            weapon: this._weaponId,
            skill: this._skillId,
            attackData: attack,
            maneuver,
            mod: this._mod,
            circumstance: this._circumstance,
            penalty: this._penalty,
            targetNumber: this._targetNumber,
            modDescription: maneuver?.modDescription?.replace("{}", "" + this._mod) ?? ""
        })
        this.close()
    }

    static async #onDefend(event, target) {
       this.element.submit()
    }

    _configureRenderOptions(options) {
        super._configureRenderOptions(options)

        if (options.window) {
            options.window.title = `Gegen einen Angriff verteidigen`
        }
        return options
    }

    #evaluateWeapons() {

        // get equipped weapons and adjust AT/PA values by basis values from actor TODO: and W/M of weapons
        const equips = this._actor.system.heldenausruestung[this._actor.system.setEquipped]
        const weapons = []

        const equippedWeapons = ["links", "rechts", "fernkampf"]

        const baseAt = {
            links: this._actor.system.at.links.aktuell, // TODO hook Beidhändigerkampf/linkhand
            rechts: this._actor.system.at.rechts.aktuell,
            fernkampf: this._actor.system.fk.aktuell,
        }
        const basePa = {
            links: this._actor.system.pa.links.aktuell, // TODO hook Beidhändigerkampf/linkhand
            rechts: this._actor.system.pa.rechts.aktuell,
            fernkampf: 0,
        }

        equippedWeapons.forEach(slot => {
            const equip = equips[slot]
            const weapon = this._actor.itemTypes["Equipment"].find(p => p._id === equip)
            if (weapon) {

                const variantWeaponSkills = [...weapon.system.rangedSkills, ...weapon.system.meleeSkills]

                variantWeaponSkills.forEach(weaponSkill => {

                    const skill = this._actor.itemTypes["Skill"].find(p => p.name === weaponSkill)
                    if (skill) {

                        const skillAt = skill.system.at
                        const skillPa = skill.system.pa

                        weapons.push({
                            isSelected: this._skillId === skill._id && this._weaponId === weapon._id,
                            weaponId: weapon._id,
                            skillId: skill._id,
                            name: weapon.name,
                            skillName: skill.name,
                            img: weapon.img,
                            combatStatistics: {
                                at: baseAt[slot] + weapon.system.attackModifier + skillAt,
                                pa: basePa[slot] + weapon.system.parryModifier + skillPa
                            }
                        })
                    }
                })
            }
        })
        // TODO: also do this for combatAction
        const links = this._actor.system.heldenausruestung[this._actor.system.setEquipped].links
        const rechts = this._actor.system.heldenausruestung[this._actor.system.setEquipped].rechts
        if (!links && !rechts) {
            const unarmedSkills = [this._actor.itemTypes["Skill"].find(p => p.name === "Ringen"), this._actor.itemTypes["Skill"].find(p => p.name === "Raufen")]

            unarmedSkills.forEach(unarmedSkill => {
                const [skillAt, skillPa] = [unarmedSkill.system.at, unarmedSkill.system.pa]

                weapons.push({
                    isSelected: this._skillId === unarmedSkill._id,
                    weaponId: "",
                    skillId: unarmedSkill._id,
                    name: unarmedSkill.name,
                    skillName: unarmedSkill.name,
                    img: "",
                    combatStatistics: {
                        at: baseAt["rechts"] + skillAt,
                        pa: basePa["rechts"] + skillPa
                    }
                })
            })
        }
        // Ausweichen as Weapon
        weapons.push({
            isSelected: this._weaponId === "Ausweichen",
            weaponId: "Ausweichen",
            skillId: "Ausweichen",
            name: "Ausweichen",
            skillName: "Ausweichen",
            img: "",
            combatStatistics: {
                at: 0,
                pa: this._actor.system.ausweichen.aktuell
            }
        })

        this._weapons = weapons.sort((a, b) => (a.isSelected ? 0 : 1) - (b.isSelected ? 0 : 1))
        return this._weapons

    }

    #evaluateManeuvers() {
        const manager = this._actionManager
        const weapon = this._weaponId !== "Ausweichen" ? this._actor.itemTypes["Equipment"].find(p => p._id === this._weaponId) : "Ausweichen"
        const skill = this._actor.itemTypes["Skill"].find(p => p._id === this._skillId)
        //const target = game.actors.get(game.scenes.current.tokens.find(p => p._id === this._targetId).actorId)
        this._maneuvers = manager.evaluate({
            //target,
            weapon,
            skill
        }).filter(p => p.type === ActionManager.DEFENSE).map(action => {
            return {
                isSelected: this._defenseManeuverId === action.name,
                id: action.name,
                name: action.name,
                type: action.type,
                source: action.source,
                cost: action.cost,
                penalty: action.eval?.mod ?? 0,
                mod: action.mod,
                modDescription: action.modDescription,
                cooldown: action.cooldown,
                activate: action.activate,
            }
        }).sort((a, b) => (a.isSelected ? 0 : 1) - (b.isSelected ? 0 : 1))
        return this._maneuvers
    }

    async _prepareContext(options) {
        const context = await super._prepareContext(options)

        context.actor = this._actor

        context.weapons = this.#evaluateWeapons()

        if (this._skillId) {
            context.maneuver = this.#evaluateManeuvers()
        }
        const maneuver = this._maneuvers?.find(p => p.id === this._defenseManeuverId)
        if (maneuver) {
            context.canMod = maneuver.mod != undefined
        }

        context.targetNumber = context.weapons.find(p => ((this._weaponId != "") || p.weaponId === this._weaponId) && p.skillId === this._skillId)?.combatStatistics.pa

        // TODO get W/M of weapon NOW

        if (this._weaponId && this._skillId && this._defenseManeuverId) {
            context.ready = true
        } else {
            context.notReadyReason = `<em>${game.i18n.format("COMBAT_DIALOG.notReadyReason.title")}</em><ul>`
            if (!this._weaponId) {
                context.notReadyReason += `<li>${game.i18n.format("COMBAT_DIALOG.notReadyReason.noWeapon")}</li>`
            }
            if (!this._skillId) {
                context.notReadyReason += `<li>${game.i18n.format("COMBAT_DIALOG.notReadyReason.noSkill")}</li>`
            }
            if (!maneuver) {
                context.notReadyReason += `<li>${game.i18n.format("COMBAT_DIALOG.notReadyReason.noManeuver")}</li>`
            }
            if (!this._targetNumber < 0) {
                context.notReadyReason += `<li>${game.i18n.format("COMBAT_DIALOG.notReadyReason.impossible")}</li>`
            }
            context.notReadyReason += "</ul>"
            context.ready = false
        }

        return context
    }

    #update(context) {
        const target = this.element.querySelector(".actions button .value")
        const targetDescription = this.element.querySelector(".modResult")
        const at = Number(context.targetNumber)
        const maneuver = this._maneuvers?.find(p => p.id === this._defenseManeuverId)
        const mod = Number(this.element.querySelector('[name="mod"]').value)
        const penalty = 0 - (maneuver?.penalty ?? 0) + (maneuver?.mod?.(mod) ?? 0) ?? 0
        const circumstance = Number(this.element.querySelector('[name="circumstance"]').value)
        this.element.querySelector('[name="penalty"]').value = penalty + circumstance
        const result = (at + circumstance + penalty)

        this._circumstance = circumstance
        this._penalty = penalty
        this._targetNumber = result
        this._mod = mod
        this._modDescription = maneuver?.modDescription?.replace("{}", "" + mod) ?? ""

        target.textContent = `(${result})`
        targetDescription.textContent = this._modDescription

        if (result <= 0 || !context.ready) {
            this.element.querySelector(".actions button").classList.remove("ready")
            this.element.querySelector(".actions button").setAttribute("disabled", true)
        } else {
            this.element.querySelector(".actions button").classList.add("ready")
            this.element.querySelector(".actions button").removeAttribute("disabled")
        }
    }

    _onRender(context, options) {
        this.#update(context)

        this.element.querySelectorAll('[name="mod"], [name="malus"], [name="circumstance"]').forEach(e => e.addEventListener('change', (event) => {
            this.#update(context)
        }))

    }


}