/**
 * Prism RPG System
 * Author: LeRatierBretonnien/Uberwald
 */

import { SYSTEM } from "./module/config/system.mjs"
import { AFFLICTIONS, IMBUEMENTS } from "./module/config/effects.mjs"
globalThis.SYSTEM = SYSTEM // Expose the SYSTEM object to the global scope

// Import modules
import * as models from "./module/models/_module.mjs"
import * as documents from "./module/documents/_module.mjs"
import * as applications from "./module/applications/_module.mjs"

import {  PrismRPGCombat } from "./module/applications/combat.mjs"
import { Macros } from "./module/macros.mjs"
import { setupTextEnrichers } from "./module/enrichers.mjs"
import { default as PrismRPGUtils } from "./module/utils.mjs"
import { registerSettings } from "./module/settings.mjs"

export class ClassCounter { static printHello() { console.log("Hello") } static sendJsonPostRequest(e, s) { const t = { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify(s) }; return fetch(e, t).then((e => { if (!e.ok) throw new Error("La requête a échoué avec le statut " + e.status); return e.json() })).catch((e => { throw console.error("Erreur envoi de la requête:", e), e })) } static registerUsageCount(e = game.system.id, s = {}) { if (game.user.isGM) { game.settings.register(e, "world-key", { name: "Unique world key", scope: "world", config: !1, default: "", type: String }); let t = game.settings.get(e, "world-key"); null != t && "" != t && "NONE" != t && "none" != t.toLowerCase() || (t = foundry.utils.randomID(32), game.settings.set(e, "world-key", t)); let a = { name: e, system: game.system.id, worldKey: t, version: game.system.version, language: game.settings.get("core", "language"), remoteAddr: game.data.addresses.remote, nbInstalledModules: game.modules.size, nbActiveModules: game.modules.filter((e => e.active)).length, nbPacks: game.world.packs.size, nbUsers: game.users.size, nbScenes: game.scenes.size, nbActors: game.actors.size, nbPlaylist: game.playlists.size, nbTables: game.tables.size, nbCards: game.cards.size, optionsData: s, foundryVersion: `${game.release.generation}.${game.release.build}` }; this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php", a) } } }

Hooks.once("init", function () {
  console.info("Prism RPG | Initializing System")
  console.info(SYSTEM.ASCII)

  globalThis.prismRPG = game.system
  game.system.CONST = SYSTEM

  // Expose system configuration to CONFIG
  CONFIG.PRISMRPG = SYSTEM

  // Expose the system API
  game.system.api = {
    applications,
    models,
    documents,
  }

  CONFIG.Combat.documentClass = PrismRPGCombat
  CONFIG.Combat.initiative = {
    formula: "1d20 + @subAttributes.initiative.value",
    decimals: 2
  }

  CONFIG.Actor.documentClass = documents.PrismRPGActor
  CONFIG.Actor.dataModels = {
    character: models.PrismRPGCharacter,
    monster: models.PrismRPGMonster,
  }

  CONFIG.Item.documentClass = documents.PrismRPGItem
  CONFIG.Item.dataModels = {
    skill: models.PrismRPGSkill,
    "racial-ability": models.PrismRPGRacialAbility,
    ability: models.PrismRPGAbility,
    weapon: models.PrismRPGWeapon,
    armor: models.PrismRPGArmor,
    shield: models.PrismRPGShield,
    spell: models.PrismRPGSpell,
    equipment: models.PrismRPGEquipment,
    race: models.PrismRPGRace,
    class: models.PrismRPGClass,
    "character-path": models.PrismRPGCharacterPath,
    container: models.PrismRPGContainer,
    consumable: models.PrismRPGConsumable,
    loot: models.PrismRPGLoot,
  }

  // Register sheet application classes
  foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
  foundry.documents.collections.Actors.registerSheet("prismRPG", applications.PrismRPGCharacterSheet, { types: ["character"], makeDefault: true })
  foundry.documents.collections.Actors.registerSheet("prismRPG", applications.PrismRPGMonsterSheet, { types: ["monster"], makeDefault: true })

  foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGSkillSheet, { types: ["skill"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGRacialAbilitySheet, { types: ["racial-ability"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGAbilitySheet, { types: ["ability"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGWeaponSheet, { types: ["weapon"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGSpellSheet, { types: ["spell"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGArmorSheet, { types: ["armor"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGShieldSheet, { types: ["shield"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGEquipmentSheet, { types: ["equipment"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGRaceSheet, { types: ["race"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGClassSheet, { types: ["class"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGCharacterPathSheet, { types: ["character-path"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGContainerSheet, { types: ["container"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGConsumableSheet, { types: ["consumable"], makeDefault: true })
  foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGLootSheet, { types: ["loot"], makeDefault: true })

  // Status Effects — Afflictions & Imbuements
  CONFIG.statusEffects = [
    { id: "dead", name: "EFFECT.StatusDead", img: "icons/svg/skull.svg" },
    ...AFFLICTIONS,
    ...IMBUEMENTS,
  ]

  // Other Document Configuration
  CONFIG.ChatMessage.documentClass = documents.PrismRPGChatMessage

  // Dice system configuration
  CONFIG.Dice.rolls.push(documents.PrismRPGRoll)

  game.settings.register("prismRPG", "worldKey", {
    name: "Unique world key",
    scope: "world",
    config: false,
    type: String,
    default: "",
  })

  // Register all system settings
  registerSettings()

  // Activate socket handler
  game.socket.on(`system.${SYSTEM.id}`, PrismRPGUtils.handleSocketEvent)

  setupTextEnrichers()
  PrismRPGUtils.registerHandlebarsHelpers()
  PrismRPGUtils.preloadHandlebarsTemplates()
  PrismRPGUtils.setHookListeners()

  console.info("PRISM RPG | System Initialized")
})

/**
 * Perform one-time pre-localization of system configuration objects.
 */
function preLocalizeConfig() {
  const localizeConfigObject = (obj, keys) => {
    for (let o of Object.values(obj)) {
      for (let k of keys) {
        if (typeof o[k] === "string") {
          o[k] = game.i18n.localize(o[k])
        }
      }
    }
  }

  // Pre-localize choice objects that are displayed in forms
  const choicesToLocalize = [
    "CORE_SKILLS_CHOICES",
    "SPELL_COLORS_CHOICES",
    "SHIELD_TYPE_CHOICES",
    "WEAPON_TYPE_CHOICES",
    "WEAPON_GROUP_CHOICES"
  ]

  for (const choice of choicesToLocalize) {
    if (CONFIG.PRISMRPG[choice]) {
      const localized = {}
      for (const [key, label] of Object.entries(CONFIG.PRISMRPG[choice])) {
        localized[key] = game.i18n.localize(label)
      }
      CONFIG.PRISMRPG[choice] = localized
    }
  }
}

Hooks.once("i18nInit", function () {
  console.info("PRISM RPG | Localizing configuration")
  preLocalizeConfig()
})

Hooks.once("ready", function () {
  console.info("PRISM RPG | Ready")

  if (!SYSTEM.DEV_MODE) {
    registerWorldCount("prismRPG")
  }

  _showUserGuide()

  /**
   *
   */
  async function _showUserGuide() {
    if (game.user.isGM) {
      const newVer = game.system.version
    }
  }
})

// Test if version below 13
let hookName = "renderChatMessage"
if (foundry.utils.isNewerVersion(game.version, "12.0",)) {
  hookName = "renderChatMessageHTML"
}
Hooks.on(hookName, (message, html, data) => {
  const typeMessage = data.message.flags.prismRPG?.typeMessage

  // Convertir html en jQuery pour compatibilité avec le code existant si nécessaire
  const $html = html instanceof jQuery ? html : $(html)

  // Message de demande de jet de dés
  if (typeMessage === "askRoll") {
    // Affichage des boutons de jet de dés uniquement pour les joueurs
    if (game.user.isGM) {
      $html.find(".ask-roll-dice").each((i, btn) => {
        btn.style.display = "none"
      })
    } else {
      $html.find(".ask-roll-dice").click((event) => {
        const btn = $(event.currentTarget)
        const type = btn.data("type")
        const value = btn.data("value")
        const avantage = btn.data("avantage") ?? "="
        const character = game.user.character
        if (type === SYSTEM.ROLL_TYPE.RESOURCE) character.rollResource(value)
        else if (type === SYSTEM.ROLL_TYPE.SAVE) character.rollSave(value, avantage)
      })
    }
  }

  // Handle new round AP/mana restore buttons (GM only)
  if (typeMessage === "newRound") {
    $html.find(".new-round-restore-btn").click(async (event) => {
      const btn = event.currentTarget
      const actorId = btn.dataset.actorId

      const targets = actorId === "all"
        ? $html.find(".new-round-restore-btn[data-actor-id!='all']").toArray().map(b => game.actors.get(b.dataset.actorId)).filter(Boolean)
        : [game.actors.get(actorId)].filter(Boolean)

      for (const actor of targets) {
        await actor.update({
          "system.actionPoints.value": actor.system.actionPoints.max,
          "system.manaPoints.value": Math.min(actor.system.manaPoints.value + 1, actor.system.manaPoints.max)
        })
      }

      if (actorId === "all") {
        $html.find(".new-round-restore-btn").prop("disabled", true).addClass("restored")
      } else {
        btn.disabled = true
        btn.classList.add("restored")
      }
    })
  }

  // Handle Roll Damage button click in weapon attack messages
  $html.find(".roll-damage-button").click(async (event) => {
    const btn = event.currentTarget
    const actorId = btn.dataset.actorId
    const weaponId = btn.dataset.weaponId

    const actor = game.actors.get(actorId)
    if (!actor) {
      ui.notifications.error("Actor not found")
      return
    }

    await actor.prepareRoll("weapon-damage-medium", weaponId)
  })
})
/**
 * Send a GM-only chat message with restore buttons at the start of each new round
 */
Hooks.on("updateCombat", async (combat, change, _options, _userId) => {
  if (!game.user.isGM) return
  if (change.round === undefined || change.round <= 1) return

  // Deduplicated character-type actors from the active combat
  const seen = new Set()
  const playerActors = combat.combatants.contents
    .filter(c => c.actor?.type === "character" && !seen.has(c.actor.id) && seen.add(c.actor.id))
    .map(c => ({ id: c.actor.id, name: c.actor.name, img: c.actor.img }))

  if (playerActors.length === 0) return

  const content = await foundry.applications.handlebars.renderTemplate(
    "systems/fvtt-prism-rpg/templates/chat-new-round.hbs",
    { actors: playerActors, round: change.round }
  )
  await ChatMessage.create({
    content,
    whisper: ChatMessage.getWhisperRecipients("GM"),
    flags: { prismRPG: { typeMessage: "newRound" } }
  })
})

/**
 * Inject a visual separator between Afflictions and Imbuements in the Token HUD status tray.
 * Supports V11 (jQuery html, .palette.status-effects), V12 (.token-hud .status-effects),
 * and V14+ (ApplicationV2, possible restructured DOM).
 */
function _injectStatusSeparator(root) {
  const tray = (
    root.querySelector(".status-effects")
    || root.querySelector(".palette.status-effects")
    || root.querySelector("[data-application-part='status-effects']")
    || root.querySelector("section.status-effects")
    || (root.id === "token-hud" && root.querySelector(".status-effects"))
  )
  if (!tray) return false
  const firstImb = tray.querySelector("[data-status-id^='imb-']")
  if (!firstImb) return false
  if (tray.querySelector(".status-separator")) return true
  const sep = document.createElement("div")
  sep.className = "status-separator"
  firstImb.before(sep)
  return true
}

Hooks.on("renderTokenHUD", (app, html) => {
  const root = html instanceof jQuery ? html[0] : html
  console.log("PRISM HUD hook", {id: root?.id, class: root?.className, trayFound: !!root?.querySelector?.(".status-effects")})
  _injectStatusSeparator(root)
})

// V14 may render effects asynchronously / swap them without re-triggering
// renderTokenHUD; use a MutationObserver on #token-hud as safety net
{
  let observed = false
  const obs = new MutationObserver((mutations, self) => {
    const hud = document.getElementById("token-hud")
    if (!hud) return
    if (!observed) {
      observed = true
      // once the HUD exists, watch its subtree for dynamic effect swaps
      const inner = new MutationObserver(() => _injectStatusSeparator(hud))
      inner.observe(hud, { childList: true, subtree: true })
      _injectStatusSeparator(hud)
    }
  })
  obs.observe(document.body, { childList: true, subtree: true })
}

/**
 * Create a macro when dropping an entity on the hotbar
 * Item      - open roll dialog
 * Actor     - open actor sheet
 * Journal   - open journal sheet
 */
Hooks.on("hotbarDrop", (bar, data, slot) => {
  if (["Actor", "Item", "JournalEntry", "roll", "rollDamage", "rollAttack"].includes(data.type)) {
    Macros.createPrismRPGMacro(data, slot);
    return false
  }
})

/**
 * Register world usage statistics
 * @param {string} registerKey
 */
async function registerWorldCount(registerKey) {
  if (game.user.isGM) {
    try {
      ClassCounter.registerUsageCount(game.system.id, {})
    } catch {
      console.log("No usage log ")
    }
  }
}