const { HandlebarsApplicationMixin } = foundry.applications.api

import { BoLRoll } from "../../controllers/bol-rolls.js"
import { BoLUtility } from "../../system/bol-utility.js"

/**
 * Base Actor Sheet for BoL system using AppV2
 * @extends {ActorSheetV2}
 */
export default class BoLBaseActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
  constructor(options = {}) {
    super(options)
    this.#dragDrop = this.#createDragDropHandlers()
  }

  #dragDrop

  /** @override */
  static DEFAULT_OPTIONS = {
    classes: ["bol", "sheet", "actor"],
    position: {
      width: 836,
      height: 807,
    },
    form: {
      submitOnChange: true,
      closeOnSubmit: false,
    },
    window: {
      resizable: true,
    },
    tabs: [
      {
        navSelector: "nav[data-group=\"primary\"]",
        contentSelector: "section.sheet-body",
        initial: "stats",
      },
    ],
    dragDrop: [{ dragSelector: ".items-list .item", dropSelector: null }],
    actions: {},
  }

  /** Tab groups state */
  tabGroups = { primary: "stats" }

  /** @override */
  async _prepareContext() {
    const actor = this.document
    return {
      actor,
      system: actor.system,
      systemFields: actor.system.schema.fields,
      config: game.bol.config,
      isGM: game.user.isGM,
      isEditable: this.isEditable,
      owner: this.document.isOwner,
      cssClass: this.options.classes.join(" "),
    }
  }

  /** @override */
  _onRender(context, options) {
    super._onRender(context, options)
    this.#dragDrop.forEach((d) => d.bind(this.element))
    this._activateTabs()
    this._activateListeners()
    this._applyBackgroundImage()
    this._activateImageEdit()
  }

  /**
   * Apply background image to the actor form
   * @private
   */
  _applyBackgroundImage() {
    const logoUrl = BoLUtility.getLogoActorSheet()
    const form = this.element.querySelector(".bol-actor-form")
    if (form) form.style.backgroundImage = `url(${logoUrl})`
  }

  /**
   * Activate image editing via FilePicker
   * @private
   */
  _activateImageEdit() {
    const img = this.element.querySelector('[data-edit="img"]')
    if (img && this.isEditable) {
      img.style.cursor = "pointer"
      img.addEventListener("click", () => {
        new FilePicker({
          type: "image",
          current: this.document.img,
          callback: (path) => this.document.update({ img: path }),
        }).browse()
      })
    }
  }

  /**
   * Activate tab navigation
   * @private
   */
  _activateTabs() {
    const nav = this.element.querySelector("nav[data-group]")
    if (!nav) return

    const group = nav.dataset.group
    const activeTab = this.tabGroups[group] || "stats"

    nav.querySelectorAll("[data-tab]").forEach((link) => {
      const tab = link.dataset.tab
      link.classList.toggle("active", tab === activeTab)
      link.addEventListener("click", (event) => {
        event.preventDefault()
        this.tabGroups[group] = tab
        nav.querySelectorAll("[data-tab]").forEach(l => l.classList.toggle("active", l.dataset.tab === tab))
        this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach(c => c.classList.toggle("active", c.dataset.tab === tab))
      })
    })

    this.element.querySelectorAll(`[data-group="${group}"][data-tab]`).forEach((content) => {
      content.classList.toggle("active", content.dataset.tab === activeTab)
    })
  }

  /**
   * Activate event listeners (replaces activateListeners with vanilla DOM)
   * @private
   */
  _activateListeners() {
    if (!this.isEditable) return

    // Item edit
    this.element.querySelectorAll(".item-edit").forEach((el) => {
      el.addEventListener("click", (ev) => {
        const li = ev.currentTarget.closest(".item")
        const item = this.actor.items.get(li?.dataset.itemId)
        item?.sheet.render(true)
      })
    })

    // Item delete
    this.element.querySelectorAll(".item-delete").forEach((el) => {
      el.addEventListener("click", (ev) => {
        const li = ev.currentTarget.closest(".item")
        const itemId = li?.dataset.itemId
        Dialog.confirm({
          title: game.i18n.localize("BOL.ui.deletetitle"),
          content: game.i18n.localize("BOL.ui.confirmdelete"),
          yes: () => {
            this.actor.deleteEmbeddedDocuments("Item", [itemId])
            li?.remove()
          },
          no: () => {},
          defaultYes: false,
        })
      })
    })

    // Item equip/unequip
    this.element.querySelectorAll(".item-equip").forEach((el) => {
      el.addEventListener("click", (ev) => {
        const li = ev.currentTarget.closest(".item")
        const item = this.actor.items.get(li?.dataset.itemId)
        if (item) this.actor.toggleEquipItem(item)
      })
    })

    // Toggle fight option
    this.element.querySelectorAll(".toggle-fight-option").forEach((el) => {
      el.addEventListener("click", (ev) => {
        const li = ev.currentTarget.closest(".item")
        this.actor.toggleFightOption(li?.dataset.itemId)
      })
    })

    // Inc/dec alchemy points
    this.element.querySelectorAll(".inc-dec-btns-alchemy").forEach((el) => {
      el.addEventListener("click", (ev) => {
        const li = ev.currentTarget.closest(".item")
        this.actor.spendAlchemyPoint(li?.dataset.itemId, 1)
      })
    })

    // Inc/dec resource buttons
    this.element.querySelectorAll(".inc-dec-btns-resource").forEach((el) => {
      el.addEventListener("click", (ev) => {
        const dataset = ev.currentTarget.dataset
        this.actor.incDecResources(dataset.target, parseInt(dataset.incr))
      })
    })

    // Generic inc/dec buttons for item fields
    this.element.querySelectorAll(".inc-dec-btns").forEach((el) => {
      el.addEventListener("click", (ev) => {
        const li = ev.currentTarget.closest(".item")
        if (!li) return
        const item = this.actor.items.get(li.dataset.itemId)
        if (!item) return
        const dataset = ev.currentTarget.dataset
        const operator = dataset.operator
        const target = dataset.target
        const incr = parseInt(dataset.incr)
        const min = parseInt(dataset.min)
        const max = parseInt(dataset.max) || 10000
        // eslint-disable-next-line no-eval
        let value = eval("item." + target) || 0
        if (operator === "minus") value = value >= min + incr ? value - incr : min
        if (operator === "plus") value = value <= max - incr ? value + incr : max
        item.update({ [target]: value })
      })
    })

    // Rollable elements
    this.element.querySelectorAll(".rollable").forEach((el) => {
      el.addEventListener("click", (ev) => this._onRoll(ev))
    })
  }

  /**
   * Handle clickable rolls (replaces _onRoll with vanilla DOM)
   * @param {Event} event
   * @private
   */
  _onRoll(event) {
    event.preventDefault()
    const element = event.currentTarget
    const dataset = element.dataset
    const rollType = dataset.rollType
    const li = element.closest(".item")
    const itemId = li?.dataset.itemId

    switch (rollType) {
      case "attribute":
        BoLRoll.attributeCheck(this.actor, dataset.key, event)
        break
      case "aptitude":
        BoLRoll.aptitudeCheck(this.actor, dataset.key, event)
        break
      case "weapon":
        BoLRoll.weaponCheck(this.actor, event)
        break
      case "spell":
        BoLRoll.spellCheck(this.actor, event)
        break
      case "alchemy":
        BoLRoll.alchemyCheck(this.actor, event)
        break
      case "protection":
        this.actor.rollProtection(itemId)
        break
      case "damage":
        this.actor.rollWeaponDamage(itemId)
        break
      case "aptitudexp":
        this.actor.incAptitudeXP(dataset.key)
        break
      case "attributexp":
        this.actor.incAttributeXP(dataset.key)
        break
      case "careerxp":
        this.actor.incCareerXP(itemId)
        break
      case "horoscope-minor":
        BoLRoll.horoscopeCheck(this.actor, event, "minor")
        break
      case "horoscope-major":
        BoLRoll.horoscopeCheck(this.actor, event, "major")
        break
      case "horoscope-major-group":
        BoLRoll.horoscopeCheck(this.actor, event, "majorgroup")
        break
      case "bougette":
        this.actor.rollBougette()
        break
      default:
        break
    }
  }

  // #region Drag-and-Drop

  #createDragDropHandlers() {
    return (this.options.dragDrop || []).map((dragDrop) =>
      new foundry.applications.ux.DragDrop.implementation({
        ...dragDrop,
        permissions: {
          dragstart: this._canDragStart.bind(this),
          drop: this._canDragDrop.bind(this),
        },
        callbacks: {
          dragstart: this._onDragStart.bind(this),
          dragover: this._onDragOver.bind(this),
          drop: this._onDrop.bind(this),
        },
      })
    )
  }

  _canDragStart(selector) {
    return this.isEditable
  }

  _canDragDrop(selector) {
    return this.isEditable
  }

  // #endregion
}
