import { ITEM_TYPES } from "../constants.js"
import { RdDItemCompetence } from "../item-competence.js"
import { ChatUtility } from "../chat-utility.js"
import { Misc } from "../misc.js"

const CODES_COMPETENCES_VOYAGE = ['Extérieur', 'Forêt', 'Montagne', 'Marais', 'Glace', 'Equitation']
const TABLEAU_FATIGUE_MARCHE = [
  {
    code: "aise", label: "Aisé", description: "Route ou chemin",
    survies: ['Extérieur', 'Equitation'],
    vitesses: [{ vitesse: 4, fatigue: 1 }, { vitesse: 6, fatigue: 2 }, { vitesse: 8, fatigue: 3 }, { vitesse: 10, fatigue: 4 }, { vitesse: 12, fatigue: 6 }],
  },
  {
    code: "malaise", label: "Malaisé", description: "Hors piste (herbes et buissons)",
    survies: ['Extérieur', 'Equitation'],
    vitesses: [{ vitesse: 4, fatigue: 2 }, { vitesse: 6, fatigue: 3 }, { vitesse: 8, fatigue: 4 }, { vitesse: 10, fatigue: 6 }],
  },
  {
    code: "difficile", label: "Difficile", description: "Hors piste (collines, forêt)",
    survies: ['Extérieur', 'Forêt', 'Glace', 'Equitation'],
    vitesses: [{ vitesse: 4, fatigue: 3 }, { vitesse: 6, fatigue: 4 }, { vitesse: 8, fatigue: 6 }],
  },
  {
    code: "tresdifficile", label: "Très difficile", description: "Hors piste (montagne, jungle, marais)",
    survies: ['Forêt', 'Montagne', 'Marais', 'Glace'],
    vitesses: [{ vitesse: 4, fatigue: 4 }, { vitesse: 6, fatigue: 6 }],
  },
]

export class DialogFatigueVoyage extends Dialog {
  static dialog = undefined
  static async create() {
    if (!game.user.isGM) {
      return
    }
    if (!DialogFatigueVoyage.dialog) {
      const parameters = {
        tableauFatigueMarche: TABLEAU_FATIGUE_MARCHE,
        playerActors: game.actors.filter(actor => actor.isPersonnageJoueur())
          .map(actor => DialogFatigueVoyage.prepareActorParameters(actor)),
        nombreHeures: 1,
      }
      DialogFatigueVoyage.setModeDeplacement(parameters, undefined, undefined)

      const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/voyage/dialog-fatigue-voyage.hbs", parameters);
      DialogFatigueVoyage.dialog = new DialogFatigueVoyage(html, parameters);
    }
    DialogFatigueVoyage.dialog.render(true);
  }

  static setModeDeplacement(parameters, code, vitesse) {
    const ligneFatigueMarche = TABLEAU_FATIGUE_MARCHE.find(it => it.code == code) ?? TABLEAU_FATIGUE_MARCHE[0]
    const rythme = ligneFatigueMarche.vitesses.find(it => it.vitesse == vitesse) ?? ligneFatigueMarche.vitesses[0]
    parameters.typeTerrain = ligneFatigueMarche
    parameters.vitesseDeplacement = rythme.vitesse
    parameters.fatigueHoraire = rythme.fatigue
    parameters.playerActors.forEach(voyageur =>
      DialogFatigueVoyage.selectSurvie(voyageur, parameters.typeTerrain.code)
    )
  }

  static prepareActorParameters(actor) {
    const actorParameters = {
      id: actor.id,
      actor: actor,
      selected: true,
      ajustementFatigue: 0,
      survies: {}
    }
    const competencesVoyage = {}
    CODES_COMPETENCES_VOYAGE.forEach(codeSurvie => {
      competencesVoyage[codeSurvie] = RdDItemCompetence.findCompetence(actor.itemTypes[ITEM_TYPES.competence], codeSurvie, { onMessage: () => { } })
    })
    TABLEAU_FATIGUE_MARCHE.forEach(terrain => {
      actorParameters.survies[terrain.code] = Misc.join(
        terrain.survies.map(survie => {
          const niveau = competencesVoyage[survie]?.system.niveau
          return `${survie}: ${niveau}`
        }),
        ', ')
    })
    return actorParameters
  }

  static selectSurvie(actorParameters, code) {
    actorParameters.survieCourante = actorParameters.survies[code]
  }

  constructor(html, parameters) {
    const options = {
      classes: ["dialog-fatigue-voyage"],
      width: 600,
      height: 'fit-content',
      'max-height': 900,
      'z-index': 99999
    }
    const conf = {
      title: "Fatigue de voyage",
      content: html,
      buttons: {}
    }
    super(conf, options);
    this.parameters = parameters
    this.controls = {}
  }

  activateListeners(html) {
    if (this.html == undefined) {
      html.find('select[name="code-terrain"]').trigger("focus")
    }
    this.html = html;
    super.activateListeners(html);

    this.html.find('select[name="code-terrain"]').change(event => this.changeParameters())
    this.html.find('select[name="vitesse-deplacement"]').change(event => this.changeParameters())
    this.html.find('input[name="nombre-heures"]').change(event => this.changeParameters())
    this.html.find('.list-item input[name="ajustement-fatigue"]').change(event => this.changeParameters())
    this.html.find('button[name="appliquer-fatigue"]').click(event => this.appliquerFatigue())
  }

  changeParameters() {
    this.changeTerrain(this.html.find('select[name="code-terrain"]').val())
    this.changeVitesse(this.html.find('select[name="vitesse-deplacement"]').val())
    this.changeNombreHeures(this.html.find('input[name="nombre-heures"]').val())
    this.setFatigue()
  }

  async changeTerrain(codeTerrain) {
    if (this.parameters.typeTerrain.code != codeTerrain) {
      const selectVitesseDeplacement = this.html.find('select[name="vitesse-deplacement"]')
      const vitesse = selectVitesseDeplacement.val()
      selectVitesseDeplacement.empty()

      DialogFatigueVoyage.setModeDeplacement(this.parameters, codeTerrain, vitesse)
      this.parameters.typeTerrain.vitesses.forEach(async rythme => {
        selectVitesseDeplacement.append(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs', rythme))
      })
      selectVitesseDeplacement.val(this.parameters.vitesseDeplacement).change()

      Promise.all(this.getActorRows()
        .map(async row => row.find('label.voyage-liste-survies').text(this.$extractActorParameters(row).survieCourante)
        ))
    }
  }

  async changeVitesse(vitesse) {
    if (this.parameters.vitesseDeplacement != vitesse) {
      DialogFatigueVoyage.setModeDeplacement(this.parameters, this.parameters.typeTerrain.code, vitesse)
    }
  }

  async changeNombreHeures(nombreHeures) {
    this.parameters.nombreHeures = parseInt(nombreHeures)
  }

  async setFatigue() {
    const baseFatigue = this.parameters.nombreHeures * this.parameters.fatigueHoraire
    this.html.find('input[name="base-fatigue"]').val(baseFatigue)
    this.updateActorTotalFatigue(baseFatigue)
  }

  async updateActorTotalFatigue(baseFatigue) {
    Promise.all(this.getActorRows()
      .map(async row => {
        const actor = this.$extractActorParameters(row)
        row.find('input[name="total-fatigue"]').val(actor.ajustement + baseFatigue)
      }))
  }

  async appliquerFatigue() {
    const fatigueBase = parseInt(this.html.find('input[name="base-fatigue"]').val() ?? 0)
    this.getActorRows()
      .map(row => this.$extractActorParameters(row))
      .filter(it => it.selected)
      .forEach(async it => {
        const perteFatigue = fatigueBase + it.ajustement
        ChatMessage.create({
          whisper: ChatUtility.getOwners(it.actor),
          content: await renderTemplate(
            'systems/foundryvtt-reve-de-dragon/templates/voyage/chat-fatigue_voyage.hbs',
            foundry.utils.mergeObject(it,
              {
                parameters: this.parameters,
                fatigueBase: fatigueBase,
                perteFatigue: perteFatigue,
                isVoyage: fatigueBase == this.parameters.nombreHeures * this.parameters.fatigueHoraire
              }, { inplace: false })
          ),
        })
        await it.actor.santeIncDec("fatigue", perteFatigue)
      })
  }

  getActorRows() {
    return jQuery.map(
      this.html.find('div.fatigue-actors-list li.list-item'),
      it => this.html.find(it))
  }


  $extractActorParameters(actorRow) {
    const actorId = actorRow.data('actor-id')
    const actorParameters = this.parameters.playerActors.find(it => it.id == actorId)
    const actor = game.actors.get(actorId)
    if (!actor) {
      ui.notifications.warn(`Acteur ${it.actorId} introuvable`)
      return {}
    }
    actorParameters.ajustement = parseInt(actorRow.find('input[name="ajustement-fatigue"]').val() ?? 0)
    actorParameters.selected = actor && actorRow.find('input[name="selectionner-acteur"]').is(':checked')
    return actorParameters
  }

  async close() {
    DialogFatigueVoyage.dialog = undefined
    await super.close()
  }


}