const { HandlebarsApplicationMixin } = foundry.applications.api

import { WastelandUtility } from "../../wasteland-utility.js"

export default class WastelandActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
  /**
   * Different sheet modes.
   * @enum {number}
   */
  static SHEET_MODES = { EDIT: 0, PLAY: 1 }

  constructor(options = {}) {
    super(options)
    this.#dragDrop = this.#createDragDropHandlers()
    this._sheetMode = this.constructor.SHEET_MODES.PLAY
  }

  #dragDrop

  /** @override */
  static DEFAULT_OPTIONS = {
    classes: ["fvtt-wasteland", "sheet", "actor"],
    position: {
      width: 650,
      height: 720,
    },
    form: {
      submitOnChange: true,
      closeOnSubmit: false,
    },
    window: {
      resizable: true,
    },
    tabs: [
      {
        navSelector: 'nav[data-group="primary"]',
        contentSelector: "section.sheet-body",
        initial: "stats",
      },
    ],
    dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
    actions: {
      editImage: WastelandActorSheet.#onEditImage,
      toggleSheet: WastelandActorSheet.#onToggleSheet,
      editItem: WastelandActorSheet.#onEditItem,
      deleteItem: WastelandActorSheet.#onDeleteItem,
      createItem: WastelandActorSheet.#onCreateItem,
      equipItem: WastelandActorSheet.#onEquipItem,
      modifyQuantity: WastelandActorSheet.#onModifyQuantity,
      incDecSante: WastelandActorSheet.#onIncDecSante,
      rollAttribut: WastelandActorSheet.#onRollAttribut,
      rollCompetence: WastelandActorSheet.#onRollCompetence,
      rollCharme: WastelandActorSheet.#onRollCharme,
      rollPouvoir: WastelandActorSheet.#onRollPouvoir,
      rollArmeOffensif: WastelandActorSheet.#onRollArmeOffensif,
      rollArmeDegats: WastelandActorSheet.#onRollArmeDegats,
      resetPredilections: WastelandActorSheet.#onResetPredilections,
      rollAssommer: WastelandActorSheet.#onRollAssommer,
      rollFuir: WastelandActorSheet.#onRollFuir,
      rollImmobiliser: WastelandActorSheet.#onRollImmobiliser,
    },
  }

  /**
   * Is the sheet currently in 'Play' mode?
   * @type {boolean}
   */
  get isPlayMode() {
    if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
    return this._sheetMode === this.constructor.SHEET_MODES.PLAY
  }

  /**
   * Is the sheet currently in 'Edit' mode?
   * @type {boolean}
   */
  get isEditMode() {
    if (this._sheetMode === undefined) this._sheetMode = this.constructor.SHEET_MODES.PLAY
    return this._sheetMode === this.constructor.SHEET_MODES.EDIT
  }

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

  /** @override */
  async _prepareContext() {
    const actor = this.document

    const context = {
      actor: actor,
      system: actor.system,
      source: actor.toObject(),
      fields: actor.schema.fields,
      systemFields: actor.system.schema.fields,
      isEditable: this.isEditable,
      isEditMode: this.isEditMode,
      isPlayMode: this.isPlayMode,
      isGM: game.user.isGM,
      config: game.system.wasteland.config,
      enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.description || "", { async: true }),
      enrichedComportement: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.comportement || "", { async: true }),
      enrichedHabitat: await foundry.applications.ux.TextEditor.implementation.enrichHTML(actor.system.biodata?.habitat || "", { async: true }),
    }
    return context
  }

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

    // Handle edit-item-data changes
    this.element.querySelectorAll('.edit-item-data').forEach(element => {
      element.addEventListener('change', async (event) => {
        const target = event.currentTarget
        const itemElement = target.closest('[data-item-id]')
        if (!itemElement) return
        
        const itemId = itemElement.dataset.itemId
        const itemType = itemElement.dataset.itemType
        const itemField = target.dataset.itemField
        const dataType = target.dataset.dtype
        const value = target.value
        
        await this.document.editItemField(itemId, itemType, itemField, dataType, value)
      })
    })

    // Activate tab navigation manually
    const nav = this.element.querySelector('nav.tabs[data-group]')
    if (nav) {
      const group = nav.dataset.group
      // Activate the current tab
      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
          this.render()
        })
      })

      // Show/hide tab content
      this.element.querySelectorAll('[data-group="' + group + '"][data-tab]').forEach(content => {
        content.classList.toggle('active', content.dataset.tab === activeTab)
      })
    }
  }

  // #region Drag-and-Drop Workflow
  /**
   * Create drag-and-drop workflow handlers for this Application
   */
  #createDragDropHandlers() {
    return []
  }

  // #region Actions

  /**
   * Handle editing the actor image
   * @param {Event} event - The triggering event
   */
  static async #onEditImage(event) {
    event.preventDefault()
    const sheet = this
    const filePicker = new FilePicker({
      type: "image",
      current: sheet.document.img,
      callback: (path) => {
        sheet.document.update({ img: path })
      },
    })
    filePicker.browse()
  }

  /**
   * Handle toggling the sheet mode
   * @param {Event} event - The triggering event
   */
  static async #onToggleSheet(event) {
    event.preventDefault()
    const sheet = this
    sheet._sheetMode = sheet._sheetMode === sheet.constructor.SHEET_MODES.PLAY ? sheet.constructor.SHEET_MODES.EDIT : sheet.constructor.SHEET_MODES.PLAY
    sheet.render()
  }

  /**
   * Handle editing an item
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onEditItem(event, target) {
    const li = target.closest(".item")
    const itemId = li?.dataset.itemId
    if (!itemId) return
    const item = this.actor.items.get(itemId)
    if (item) item.sheet.render(true)
  }

  /**
   * Handle deleting an item
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onDeleteItem(event, target) {
    const li = target.closest(".item")
    await WastelandUtility.confirmDelete(this, li)
  }

  /**
   * Handle creating an item
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onCreateItem(event, target) {
    const itemType = target.dataset.type
    await this.actor.createEmbeddedDocuments("Item", [{ name: `Nouveau ${itemType}`, type: itemType }], { renderSheet: true })
  }

  /**
   * Handle equipping an item
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onEquipItem(event, target) {
    const li = target.closest(".item")
    const itemId = li?.dataset.itemId
    if (!itemId) return
    await this.actor.equipItem(itemId)
  }

  /**
   * Handle modifying item quantity
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onModifyQuantity(event, target) {
    const li = target.closest(".item")
    const itemId = li?.dataset.itemId
    if (!itemId) return
    
    const item = this.actor.items.get(itemId)
    if (!item) return
    
    const qty = parseInt(target.dataset.qty) || 0
    const currentQty = item.system.quantite || 0
    const newQty = Math.max(0, currentQty + qty)
    
    await item.update({ 'system.quantite': newQty })
  }

  /**
   * Handle modifying santé/psyché
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onIncDecSante(event, target) {
    const field = target.dataset.field
    const value = parseInt(target.dataset.value) || 0
    
    if (field === 'psyche') {
      await this.actor.update({ 'system.psyche.value': this.actor.system.psyche.value + value })
    } else if (field === 'nonletaux') {
      await this.actor.update({ 'system.sante.nonletaux': this.actor.system.sante.nonletaux + value })
    } else if (field === 'letaux') {
      await this.actor.update({ 'system.sante.letaux': this.actor.system.sante.letaux + value })
    }
  }

  /**
   * Handle rolling an attribute
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollAttribut(event, target) {
    const attrKey = target.dataset.attrKey
    await this.actor.rollAttribut(attrKey)
  }

  /**
   * Handle rolling a competence
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollCompetence(event, target) {
    const li = target.closest(".item")
    const itemId = li?.dataset.itemId
    const attrKey = target.dataset.attrKey
    if (!itemId) return
    await this.actor.rollCompetence(attrKey, itemId)
  }

  /**
   * Handle rolling a charme
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollCharme(event, target) {
    const li = target.closest(".item")
    const itemId = li?.dataset.itemId
    if (!itemId) return
    await this.actor.rollCharme(itemId)
  }

  /**
   * Handle rolling a pouvoir
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollPouvoir(event, target) {
    const li = target.closest(".item")
    const itemId = li?.dataset.itemId
    if (!itemId) return
    await this.actor.rollPouvoir(itemId)
  }

  /**
   * Handle rolling weapon attack
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollArmeOffensif(event, target) {
    const li = target.closest(".item")
    const itemId = li?.dataset.itemId
    if (!itemId) return
    await this.actor.rollArmeOffensif(itemId)
  }

  /**
   * Handle rolling weapon damage
   * @param {Event} event - The triggering event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollArmeDegats(event, target) {
    const li = target.closest(".item")
    const itemId = li?.dataset.itemId
    if (!itemId) return
    await this.actor.rollArmeDegats(itemId)
  }

  /**
   * Handle resetting all predilections
   * @param {Event} event - The originating click event
   * @param {HTMLElement} target - The target element
   */
  static async #onResetPredilections(event, target) {
    await this.actor.resetAllPredilections()
  }

  /**
   * Handle Assommer roll
   * @param {Event} event - The originating click event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollAssommer(event, target) {
    await this.actor.rollAssommer()
  }

  /**
   * Handle Fuir roll
   * @param {Event} event - The originating click event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollFuir(event, target) {
    await this.actor.rollFuir()
  }

  /**
   * Handle Immobiliser roll
   * @param {Event} event - The originating click event
   * @param {HTMLElement} target - The target element
   */
  static async #onRollImmobiliser(event, target) {
    await this.actor.rollImmobiliser()
  }
}
