const { HandlebarsApplicationMixin } = foundry.applications.api

import { LesOubliesUtility } from "../../les-oublies-utility.js"

export default class LesOubliesActorSheet extends HandlebarsApplicationMixin(foundry.applications.sheets.ActorSheetV2) {
  static SHEET_MODES = { EDIT: 0, PLAY: 1 }

  static DEFAULT_OPTIONS = {
    classes: ["fvtt-les-oublies", "sheet", "actor"],
    position: {
      width: 980,
      height: 860,
    },
    window: {
      resizable: true,
    },
    form: {
      submitOnChange: true,
      closeOnSubmit: false,
    },
    dragDrop: [{ dragSelector: ".item-card", dropSelector: "form" }],
    actions: {
      toggleSheet: LesOubliesActorSheet.#onToggleSheet,
      editImage: LesOubliesActorSheet.#onEditImage,
      createItem: LesOubliesActorSheet.#onCreateItem,
      editItem: LesOubliesActorSheet.#onEditItem,
      deleteItem: LesOubliesActorSheet.#onDeleteItem,
      openRoll: LesOubliesActorSheet.#onOpenRoll,
      openConfrontation: LesOubliesActorSheet.#onOpenConfrontation,
      openInitiative: LesOubliesActorSheet.#onOpenInitiative,
      rollProfile: LesOubliesActorSheet.#onRollProfile,
      rollSkill: LesOubliesActorSheet.#onRollSkill,
      useWeapon: LesOubliesActorSheet.#onUseWeapon,
      resolveWeaponDamage: LesOubliesActorSheet.#onResolveWeaponDamage,
      toggleEquipped: LesOubliesActorSheet.#onToggleEquipped,
      useSpell: LesOubliesActorSheet.#onUseSpell,
      openCombatPreset: LesOubliesActorSheet.#onOpenCombatPreset,
      openThreadHarvest: LesOubliesActorSheet.#onOpenThreadHarvest,
      openLinkedActor: LesOubliesActorSheet.#onOpenLinkedActor,
      transferThread: LesOubliesActorSheet.#onTransferThread,
    },
  }

  _sheetMode = this.constructor.SHEET_MODES.EDIT

  get isEditMode() {
    return this._sheetMode === this.constructor.SHEET_MODES.EDIT
  }

  get isPlayMode() {
    return this._sheetMode === this.constructor.SHEET_MODES.PLAY
  }

  async _prepareContext() {
    const config = CONFIG.LESOUBLIES
    const enriched = await LesOubliesUtility.prepareEnrichedHtml("Actor", this.document.type, this.document.system)
    const choiceSets = {
      profileOptions: config.profiles.map((profile) => ({ value: profile.id, label: profile.label })),
      personnageSizeOptions: LesOubliesUtility.createRangeChoices(1, 4, config.sizes),
      creatureSizeOptions: LesOubliesUtility.createRangeChoices(1, 8, config.sizes),
    }

    return {
      actor: this.document,
      system: this.document.system,
      source: this.document.toObject(),
      fields: this.document.schema.fields,
      systemFields: this.document.system.schema.fields,
      isEditable: this.isEditable,
      isEditMode: this.isEditMode,
      isPlayMode: this.isPlayMode,
      isGM: game.user.isGM,
      config,
      choiceSets,
      enriched,
      enrichedDescription: foundry.utils.getProperty(enriched, "biodata.description") ?? foundry.utils.getProperty(enriched, "description") ?? "",
    }
  }

  _prepareWeaponEntries(items = []) {
    return items.map((item) => ({
      ...item.toObject(),
      id: item.id,
      displayDamage: LesOubliesUtility.formatWeaponDamage(this.document, item),
    }))
  }

  _onRender(context, options) {
    super._onRender(context, options)
  }

  _onDragStart(event) {
    const itemElement = event.currentTarget?.closest?.("[data-item-id]") ?? event.target?.closest?.("[data-item-id]")
    const itemId = itemElement?.dataset?.itemId
    const item = itemId ? this.document.items.get(itemId) : null
    if (!item || !event.dataTransfer) return

    event.dataTransfer.setData("text/plain", JSON.stringify(item.toDragData()))
  }

  _canDragStart() {
    return this.isEditable
  }

  _canDragDrop() {
    return this.isEditable
  }

  async _onDrop(event) {
    const data = TextEditor.getDragEventData(event)
    if (data.type !== "Item" || !data.uuid) return
    const item = await fromUuid(data.uuid)
    if (!item) return
    return this._onDropItem(item)
  }

  async _onDropItem(item) {
    const itemData = item.toObject()
    delete itemData._id
    return this.document.createEmbeddedDocuments("Item", [itemData], { renderSheet: false })
  }

  static #onToggleSheet() {
    const modes = this.constructor.SHEET_MODES
    this._sheetMode = this.isEditMode ? modes.PLAY : modes.EDIT
    this.render()
  }

  static async #onEditImage(event, target) {
    const attr = target.dataset.edit
    const current = foundry.utils.getProperty(this.document, attr)
    const FilePicker = foundry.applications.apps.FilePicker.implementation
    const fp = new FilePicker({
      current,
      type: "image",
      callback: (path) => this.document.update({ [attr]: path }),
      top: this.position.top + 40,
      left: this.position.left + 10,
    })
    return fp.browse()
  }

  static async #onCreateItem(event, target) {
    const type = target.dataset.type
    if (!type) return
    const label = game.i18n.localize(`TYPES.Item.${type}`)
    const itemData = {
      name: label,
      type,
      img: LesOubliesUtility.getDefaultItemImage(type),
    }
    if (type === "competence") {
      itemData.system = {
        profileKey: CONFIG.LESOUBLIES.profiles[0]?.id ?? "",
      }
    }
    return this.document.createEmbeddedDocuments("Item", [itemData])
  }

  static async #onEditItem(event, target) {
    const itemId = target.dataset.itemId
    const item = this.document.items.get(itemId)
    if (item) item.sheet.render(true)
  }

  static async #onDeleteItem(event, target) {
    const itemId = target.dataset.itemId
    const item = this.document.items.get(itemId)
    if (item) await item.delete()
  }

  static async #onOpenRoll() {
    await this.document.openTestRollDialog()
  }

  static async #onOpenConfrontation() {
    await this.document.openConfrontationRollDialog()
  }

  static async #onOpenInitiative() {
    await this.document.openInitiativeRollDialog()
  }

  static async #onRollProfile(event, target) {
    const profileKey = target.dataset.profileKey
    if (!profileKey) return
    await this.document.rollProfile(profileKey)
  }

  static async #onRollSkill(event, target) {
    const itemId = target.dataset.itemId
    if (!itemId) return
    await this.document.rollCompetence(itemId)
  }

  static async #onUseWeapon(event, target) {
    const itemId = target.dataset.itemId
    if (!itemId) return
    await this.document.openAttackRollDialog({ itemId })
  }

  static async #onResolveWeaponDamage(event, target) {
    const itemId = target.dataset.itemId
    if (!itemId) return
    await this.document.openDamageDialog({ itemId })
  }

  static async #onToggleEquipped(event, target) {
    const itemId = target.dataset.itemId
    if (!itemId) return
    const item = this.document.items.get(itemId)
    if (!item || !("equipped" in (item.system ?? {}))) return
    await item.update({ "system.equipped": !item.system.equipped })
  }

  static async #onUseSpell(event, target) {
    const itemId = target.dataset.itemId
    if (!itemId) return
    await this.document.openSpellActivationDialog(itemId)
  }

  static async #onOpenCombatPreset(event, target) {
    const actionKey = target.dataset.preset
    if (!actionKey) return
    await this.document.openCombatPresetDialog(actionKey)
  }

  static async #onOpenThreadHarvest() {
    await this.document.openThreadHarvestDialog()
  }

  static async #onOpenLinkedActor(event, target) {
    const actorId = target.dataset.actorId
    if (!actorId) return
    const actor = game.actors.get(actorId)
    if (actor) actor.sheet.render(true)
  }

  static async #onTransferThread(event, target) {
    const resourceKey = target.dataset.resourceKey
    const direction = target.dataset.direction || "toCompany"
    if (!resourceKey || !this.document?.transferThreadReserve) return

    const row = target.closest("[data-transfer-row]")
    const amountField = row?.querySelector?.("[data-transfer-amount]")
    const amount = Math.max(Math.trunc(Number(amountField?.value ?? 1)), 0)
    if (amount < 1) {
      ui.notifications.warn("Indiquez une quantité à transférer.")
      return
    }

    const success = await this.document.transferThreadReserve(resourceKey, amount, direction)
    if (!success) {
      ui.notifications.warn("Transfert impossible avec les réserves actuelles.")
      return
    }

    this.render()
  }
}
