import { SYSTEM_RDD, SYSTEM_SOCKET_ID, RDD_CONFIG, ITEM_TYPES } from "./constants.js"

const RDD_INFO_MESSAGE_URL = "https://gitea.scriptarium.org/Scriptarium/foundryvtt-reve-de-dragon/raw/branch/v13/info-message.html"

import { RdDUtility } from "./rdd-utility.js"
import { TMRUtility } from "./tmr-utility.js"
import { TMRRencontres } from "./tmr-rencontres.js"
import { RdDCalendrier } from "./time/rdd-calendrier.js"
import { RdDTimestamp } from "./time/rdd-timestamp.js"
import { DialogChronologie } from "./dialog-chronologie.js"

import { RdDResolutionTable } from "./rdd-resolution-table.js"
import { RdDTokenHud } from "./rdd-token-hud.js"
import { RdDCommands } from "./rdd-commands.js"
import { ChatUtility } from "./chat-utility.js"
import { StatusEffects } from "./settings/status-effects.js"
import { RdDCompendiumOrganiser } from "./rdd-compendium-organiser.js"
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"
import { RdDHotbar } from "./rdd-hotbar-drop.js"
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"
import { RdDDice } from "./rdd-dice.js"
import { RdDPossession } from "./combat/rdd-possession.js";
import { Misc } from "./misc.js"

import { SystemCompendiums } from "./settings/system-compendiums.js"
import { Environnement } from "./environnement.js"

import { RdDActor } from "./actor.js"
import { RdDBaseActor } from "./actor/base-actor.js"
import { RdDCreature } from "./actor/creature.js"
import { RdDCommerce } from "./actor/commerce.js"
import { RdDEntite } from "./actor/entite.js"
import { RdDVehicule } from "./actor/vehicule.js"

// V2 sheets imported via sheets.* below

import { RdDItem } from "./item.js"

import * as models from "./models/_module.mjs"
import * as items from "./documents/_module.mjs"
import * as sheets from "./applications/sheets/_module.mjs"

import { RdDItemArme } from "./item/arme.js"
import { RdDItemArmure } from "./item/armure.js"
import { RdDItemBlessure } from "./item/blessure.js"
import { RdDItemCompetence } from "./item-competence.js"
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
import { RdDItemGemme } from "./item/gemme.js"
import { RdDItemMaladie } from "./item/maladie.js"
import { RdDItemPoison } from "./item/poison.js"
import { RdDItemPotion } from "./item/potion.js"
import { RdDItemService } from "./item/service.js"
import { RdDItemRace } from "./item/race.js"
import { RdDItemSigneDraconique } from "./item/signedraconique.js"
import { RdDItemSort } from "./item-sort.js"
import { RdDItemTache } from "./item/tache.js"
import { RdDRencontre } from "./item/rencontre.js"

import { AppAstrologie } from "./sommeil/app-astrologie.js"
import { AutoAdjustDarkness } from "./time/auto-adjust-darkness.js"
import { RdDTMRDialog } from "./rdd-tmr-dialog.js"
import { OptionsAvancees } from "./settings/options-avancees.js"
import { ExportScriptarium } from "./actor/export-scriptarium/export-scriptarium.js"
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js"
import { RdDStatBlockParser } from "./apps/rdd-import-stats.js"
import { RdDJournalSheet } from "./journal/journal-sheet.mjs"
import { RdDCombat } from "./combat/rdd-combat.js"
import { PasseArme } from "./combat/passe-arme.mjs"
import { Migrations } from './migrations.js'

import RollDialog from "./roll/roll-dialog.mjs"
import ChatRollResult from "./roll/chat-roll-result.mjs"
import ExportPdf from "./actor/export-pdf/export-pdf.mjs"
import { DialogFlushByDate } from "./chat/dialog-flush-by-date.mjs"
import { Remote } from "./remote.mjs"
import { RdDActiveEffect } from "./effect/base-active-effect.js"

/**
 * RdD system
 * Author: LeRatierBretonnien
 * Software License: GNU GPLv3
 */
export class SystemReveDeDragon {

  static start() {
    const system = new SystemReveDeDragon()
    Hooks.once('init', () => system.onInit())
    Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d))
    Hooks.once('ready', () => system.onReady())
  }

  constructor() {
    this.config = RDD_CONFIG
    this.RdDUtility = RdDUtility
    this.RdDHotbar = RdDHotbar
    this.RdDStatBlockParser = RdDStatBlockParser
    this.itemClasses = {
      monnaie: items.RdDItemMonnaie,
      munition: items.RdDItemMunition,
      arme: RdDItemArme,
      armure: RdDItemArmure,
      blessure: RdDItemBlessure,
      competence: RdDItemCompetence,
      competencecreature: RdDItemCompetenceCreature,
      gemme: RdDItemGemme,
      maladie: RdDItemMaladie,
      ombre: items.RdDItemOmbre,
      poison: RdDItemPoison,
      potion: RdDItemPotion,
      queue: items.RdDItemQueue,
      race: RdDItemRace,
      rencontre: RdDRencontre,
      service: RdDItemService,
      signedraconique: RdDItemSigneDraconique,
      souffle: items.RdDItemSouffle,
      tache: RdDItemTache,
      tarot: items.RdDItemTarot,
      tete: items.RdDItemTete,
      chant: items.RdDItemChant,
      musique: items.RdDItemMusique,
      danse: items.RdDItemDanse,
      jeu: items.RdDItemJeu,
      recettealchimique: items.RdDItemRecetteAlchimique,
      recettecuisine: items.RdDItemRecetteCuisine,
    }
    this.actorClasses = {
      commerce: RdDCommerce,
      creature: RdDCreature,
      entite: RdDEntite,
      personnage: RdDActor,
      vehicule: RdDVehicule,
    }
  }

  /* -------------------------------------------- */
  /*  Foundry VTT Initialization                  */
  /* -------------------------------------------- */
  onInit() {
    game.system.rdd = this

    globalThis.RdD = game.system

    this.AppAstrologie = AppAstrologie
    this.Dice = RdDDice

    console.log(`Initializing Reve de Dragon System Settings`)

    // preload handlebars templates
    RdDUtility.preloadHandlebarsTemplates()
    AppPersonnageAleatoire.preloadHandlebars()
    RdDItemSort.preloadHandlebars()

    /* -------------------------------------------- */
    ReglesOptionnelles.initSettings()
    OptionsAvancees.initSettings()
    AutoAdjustDarkness.initSettings()
    RdDTimestamp.initSettings()
    RdDCalendrier.initSettings()
    SystemCompendiums.initSettings()
    DialogChronologie.initSettings()
    EffetsDraconiques.initSettings()
    RdDTMRDialog.initSettings()
    Environnement.initSettings()

    this.initSettings()

    /* -------------------------------------------- */
    // Set an initiative formula for the system
    CONFIG.Combat.initiative = { formula: "1+(1d6/10)", decimals: 2 }

    /* -------------------------------------------- */
    console.log(`Initializing Reve de Dragon Socket handlers`)
    game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => {
      console.log(">>>>> MSG RECV", sockmsg)
      try {
        Remote.onSocketMessage(sockmsg)
        RdDUtility.onSocketMessage(sockmsg)
        PasseArme.onSocketMessage(sockmsg)
        ChatUtility.onSocketMessage(sockmsg)
        RdDBaseActor.onSocketMessage(sockmsg)
      } catch (e) {
        console.error('game.socket.on(SYSTEM_SOCKET_ID) Exception: ', sockmsg, ' => ', e)
      }
    })

    /* -------------------------------------------- */
    // Define custom Entity classes
    console.log(`Initializing Reve de Dragon Documents`)
    CONFIG.Actor.documentClass = RdDBaseActor
    CONFIG.Actor.dataModels = {
      personnage: models.RdDModelPersonnage,
      creature: models.RdDModelCreature,
      entite: models.RdDModelEntite,
      vehicule: models.RdDModelVehicule,
      commerce: models.RdDModelCommerce,
    }
    CONFIG.ActiveEffect.documentClass = RdDActiveEffect
    CONFIG.Item.documentClass = RdDItem
    CONFIG.Item.dataModels = {
      monnaie: models.RdDModelMonnaie,
      munition: models.RdDModelMunition,
      tarot: models.RdDModelTarot,
      tete: models.RdDModelTete,
      queue: models.RdDModelQueue,
      souffle: models.RdDModelSouffle,
      ombre: models.RdDModelOmbre,
      chant: models.RdDModelChant,
      musique: models.RdDModelMusique,
      danse: models.RdDModelDanse,
      jeu: models.RdDModelJeu,
      recettealchimique: models.RdDModelRecetteAlchimique,
      recettecuisine: models.RdDModelRecetteCuisine,
      arme: models.RdDModelArme,
      armure: models.RdDModelArmure,
      objet: models.RdDModelObjet,
      conteneur: models.RdDModelConteneur,
      nourritureboisson: models.RdDModelNourritureBoisson,
      gemme: models.RdDModelGemme,
      extraitpoetique: models.RdDModelExtraitPoetique,
      nombreastral: models.RdDModelNombreAstral,
      casetmr: models.RdDModelCaseTMR,
      sortreserve: models.RdDModelSortReserve,
      meditation: models.RdDModelMeditation,
      oeuvre: models.RdDModelOeuvre,
      livre: models.RdDModelLivre,
      faune: models.RdDModelFaune,
      herbe: models.RdDModelHerbe,
      plante: models.RdDModelPlante,
      ingredient: models.RdDModelIngredient,
      service: models.RdDModelService,
      tache: models.RdDModelTache,
      blessure: models.RdDModelBlessure,
      maladie: models.RdDModelMaladie,
      poison: models.RdDModelPoison,
      competence: models.RdDModelCompetence,
      competencecreature: models.RdDModelCompetenceCreature,
      potion: models.RdDModelPotion,
      signedraconique: models.RdDModelSigneDraconique,
      sort: models.RdDModelSort,
      race: models.RdDModelRace,
      rencontre: models.RdDModelRencontre,
      empoignade: models.RdDModelEmpoignade,
      possession: models.RdDModelPossession,
    }
    CONFIG.RDD = {
      resolutionTable: RdDResolutionTable.resolutionTable,
      carac_array: RdDUtility.getCaracArray(),
      ajustementsConditions: RdDUtility.getAjustementsConditions(),
      difficultesLibres: RdDUtility.getDifficultesLibres()
    }

    /* -------------------------------------------- */
    // Register sheet application classes
    foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
    foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet)

    sheets.RdDBaseActorSheetV2.registerAll(
      sheets.RdDCommerceSheetV2,
      sheets.RdDActorSheetV2,
      sheets.RdDCreatureSheetV2,
      sheets.RdDActorVehiculeSheetV2,
      sheets.RdDActorEntiteSheetV2,
    )
    sheets.RdDActorExportSheetV2.init()
    sheets.RdDActorExportSheetV2.register()

    sheets.RdDItemBaseSheet.registerAll(
      sheets.RdDMonnaieSheet,
      sheets.RdDMunitionSheet,
      sheets.RdDTarotSheet,
      sheets.RdDTeteSheet,
      sheets.RdDQueueSheet,
      sheets.RdDSouffleSheet,
      sheets.RdDOmbreSheet,
      sheets.RdDChantSheet,
      sheets.RdDMusiqueSheet,
      sheets.RdDDanseSheet,
      sheets.RdDJeuSheet,
      sheets.RdDRecetteAlchimiqueSheet,
      sheets.RdDRecetteCuisineSheet,
      sheets.RdDArmeSheet,
      sheets.RdDArmureSheet,
      sheets.RdDObjetSheet,
      sheets.RdDConteneurSheet,
      sheets.RdDNourritureBoissonSheet,
      sheets.RdDGemmeSheet,
      sheets.RdDExtraitPoetiqueSheet,
      sheets.RdDNombreAstralSheet,
      sheets.RdDCaseTMRSheet,
      sheets.RdDSortReserveSheet,
      sheets.RdDMeditationSheet,
      sheets.RdDOeuvreSheet,
      sheets.RdDLivreSheet,
      sheets.RdDFauneSheet,
      sheets.RdDHerbeSheet,
      sheets.RdDPlanteSheet,
      sheets.RdDIngredientSheet,
      sheets.RdDServiceSheet,
      sheets.RdDTacheSheet,
      sheets.RdDBlessureSheet,
      sheets.RdDMaladieSheet,
      sheets.RdDPoisonSheet,
      sheets.RdDCompetenceSheet,
      sheets.RdDCompetenceCreatureSheet,
      sheets.RdDPotionSheet,
      sheets.RdDSigneDraconiqueSheet,
      sheets.RdDSortSheet,
      sheets.RdDRaceSheet,
      sheets.RdDRencontreSheet,
      sheets.RdDEmpoignadeSheet,
      sheets.RdDPossessionSheet,
    )

    RdDJournalSheet.register()

    // préparation des différents modules
    console.log(`Initializing Reve de Dragon Hooks and handlers`)
    CONFIG.Combat.documentClass = RdDCombat
    ChatUtility.init()
    RdDUtility.initHooks()
    RdDDice.init()
    RdDCommands.init()
    RdDCombat.init()
    RdDTokenHud.init()
    RdDBaseActor.init()
    RdDCompendiumOrganiser.init()
    EffetsDraconiques.init()
    TMRUtility.init()
    RdDHotbar.initHooks()
    RdDPossession.init()
    TMRRencontres.init()
    ExportScriptarium.init()
    ExportPdf.init()
    RollDialog.init()
    ChatRollResult.init()
    DialogFlushByDate.init()
  }

  initSettings() {
    // TODO: déplacer vers les modules correspondants
    game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", {
      name: "Accorder le rêve aux entités",
      hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar",
      scope: "world",
      config: true,
      type: String,
      choices: {
        "avant-attaque": "Avant l'attaque",
        "avant-defense": "Avant la défense",
        "avant-encaissement": "Avant l'encaissement",
      },
      default: "avant-encaissement"
    })

    /* -------------------------------------------- */
    game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", {
      name: "Supprimer les dialogues de combat",
      hint: "Si désactivée, tous les dialogues de combat sont conservés dans la conversation",
      scope: "world",
      config: true,
      default: true,
      type: Boolean
    })

    /* -------------------------------------------- */
    game.settings.register(SYSTEM_RDD, "activer-sons-audio", {
      name: "Activer les bruitages intégrés",
      hint: "Si activé, certaines actions en jeu déclenchent un son d'ambiance",
      scope: "world",
      config: true,
      default: true,
      type: Boolean
    })

    /* -------------------------------------------- */
    game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", {
      name: "Notifier de la famine et la soif pour",
      hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant",
      scope: "world",
      config: true,
      type: String,
      choices: {
        "aucun": "ni la famine, ni la soif",
        "famine": "seulement la famine",
        "famine-soif": "la famine et la soif",
      },
      default: "aucun"
    })

    /* -------------------------------------------- */
    game.settings.register(SYSTEM_RDD, "info-msg-timeout", {
      name: "Gestion du timeout d'affichage du message d'information",
      scope: "world",
      config: false,
      type: Number,
      default: 0
    })

    /* -------------------------------------------- */
    game.settings.register(SYSTEM_RDD, "cd-suivi-journal", {
      name: "Journal de suivi Château Dormant",
      hint: "ID du journal où enregistrer le récapitulatif quotidien des personnages (stress, moral, événements). Laissez vide pour désactiver.",
      scope: "world",
      config: true,
      type: String,
      default: ""
    })
  }

  async onReady() {
    const asciiLogo = `██████╗ ███████╗██╗   ██╗███████╗    ██████╗ ███████╗    ██████╗ ██████╗  █████╗  ██████╗  ██████╗ ███╗   ██╗
██╔══██╗██╔════╝██║   ██║██╔════╝    ██╔══██╗██╔════╝    ██╔══██╗██╔══██╗██╔══██╗██╔════╝ ██╔═══██╗████╗  ██║
██████╔╝█████╗  ██║   ██║█████╗      ██║  ██║█████╗      ██║  ██║██████╔╝███████║██║  ███╗██║   ██║██╔██╗ ██║
██╔══██╗██╔══╝  ╚██╗ ██╔╝██╔══╝      ██║  ██║██╔══╝      ██║  ██║██╔══██╗██╔══██║██║   ██║██║   ██║██║╚██╗██║
██║  ██║███████╗ ╚████╔╝ ███████╗    ██████╔╝███████╗    ██████╔╝██║  ██║██║  ██║╚██████╔╝╚██████╔╝██║ ╚████║
╚═╝  ╚═╝╚══════╝  ╚═══╝  ╚══════╝    ╚═════╝ ╚══════╝    ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝  ╚═════╝ ╚═╝  ╚═══╝
`
    console.log(asciiLogo)

    /* -------------------------------------------- */
    /*  Foundry VTT Initialization                  */
    /* -------------------------------------------- */
    game.system.rdd.calendrier = new RdDCalendrier()
    if (Misc.isFirstConnectedGM()) {
      try {
        new Migrations().migrate()
      }
      catch (erreur) {
        const message = `<p>Erreur lors de la migration du système Rêve de Dragon: ${erreur}</p><p>Plus de détails sont sans doute disponibles dans la console de Foundry/du navigateur.</p><p>Merci de nous signaler cetter erreur qu'on puisse ous aider et réparer le problème.</p>`
        ui.notifications.error(message)
        await ChatMessage.create({
          user: game.user.id,
          content: message
        })
      }
      this.messageDeBienvenue()
      import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
        console.log("ClassCounter loaded", moduleCounter)
        moduleCounter.ClassCounter.registerUsageCount()
      }).catch(err =>
        console.log("No stats available, giving up.")
      )
    }

    StatusEffects.onReady()
    RdDDice.onReady()
    RollDialog.onReady()
    ChatRollResult.onReady()
    RdDItemCompetence.onReady()

    /* -------------------------------------------- */
    /* Affiche/Init le calendrier */
    setTimeout(() => game.system.rdd.calendrier.display().catch(e => console.warn("Calendrier display error:", e?.message || e)), 100)
    // Avertissement si joueur sans personnage
    if (!game.user.isGM && game.user.character == undefined) {
      ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !")
      ChatMessage.create({
        content: `<b>ATTENTION</b> Le joueur ${game.user.name} n'est connecté à aucun personnage !`,
        user: game.user.id
      })
    }

    this.setupAccueil()
  }

  async setupAccueil() {
    let exists = game.scenes.find(j => j.name == "Accueil RdD");
    if (!exists) {
      const scenes = await SystemCompendiums.loadCompendium("foundryvtt-reve-de-dragon.scenes-rdd")
      let newDocuments = scenes.filter(i => i.name == "Accueil RdD");
      await game.scenes.documentClass.create(newDocuments);
      game.scenes.find(i => i.name == "Accueil RdD").activate();
    }
  }

  /* -------------------------------------------- */
  messageDeBienvenue() {
    if (game.user.isGM) {
      ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">')
      ChatMessage.create({
        user: game.user.id,
        content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span>
      <br>Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}
      <br>La commande <code>/aide</code> dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.</div>
      ` })
      // Get last message display time
      const lastDisplay = game.settings.get(SYSTEM_RDD, "info-msg-timeout") || 0
      const now = Date.now()
      const oneDayMs = 24 * 60 * 60 * 1000
      if (now - lastDisplay < oneDayMs) {
        return // Already displayed in the last 24 hours
      }
      // Update last display time
      game.settings.set(SYSTEM_RDD, "info-msg-timeout", now)
      // Try to fetch the welcome message from the github repo RDD_INFO_MESSAGE_URL
      fetch(RDD_INFO_MESSAGE_URL)
        .then(response => response.text())
        .then(html => {
          console.log("Fetched welcome message:", html);
          ChatMessage.create({
            user: game.user.id,
            whisper: [game.user.id],
            content: html
          });
        })
        .catch(error => {
          console.error("Error fetching welcome message:", error);
        });
    }
  }

  roll(rollData, actors, options) {
    RollDialog.create(rollData, actors, options)
  }
}

SystemReveDeDragon.start()
