/* -------------------------------------------- */
import { RdDCalendrierEditeur } from "./rdd-calendrier-editeur.js";
import { RdDAstrologieEditeur } from "./rdd-astrologie-editeur.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDUtility } from "./rdd-utility.js";

/* -------------------------------------------- */
const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/'
const heuresList = [ "vaisseau", "sirene", "faucon", "couronne", "dragon", "epees", "lyre", "serpent", "poissonacrobate", "araignee", "roseau", "chateaudormant" ];
const heuresDef = { "vaisseau": { label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' },
                    "sirene": { label: "Sirène", lettreFont: 'S', saison: "printemps", heure: 1, icon: 'hd02.svg' },
                    "faucon": { label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' },
                    "couronne": { label: "Couronne", lettreFont: 'C', saison: "ete", heure: 3, icon: 'hd04.svg' },
                    "dragon": { label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' },
                    "epees": { label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' },
                    "lyre": { label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' },
                    "serpent": { label: "Serpent", lettreFont: 's', saison: "automne", heure: 7, icon: 'hd08.svg' },
                    "poissonacrobate": { label: "Poisson Acrobate", lettreFont: 'p', saison: "automne", heure: 8, icon: 'hd09.svg'  },
                    "araignee": { label: "Araignée", lettreFont: 'a', saison: "hiver", heure: 9, icon: 'hd10.svg' },
                    "roseau": { label: "Roseau", lettreFont: 'r', saison: "hiver", heure: 10, icon: 'hd11.svg' },
                    "chateaudormant": { label: "Château Dormant", lettreFont: 'c', saison: "hiver", heure: 11, icon: 'hd12.svg' }
                };
const saisonsDef = { "printemps": { label: "Printemps"},
                      "ete": { label: "Eté"},
                      "automne": { label: "Automne"},
                      "hiver": { label: "Hiver"}
                   };
const RDD_JOUR_PAR_MOIS = 28;
const MAX_NOMBRE_ASTRAL = 12;

/* -------------------------------------------- */
export class RdDCalendrier extends Application {

/* -------------------------------------------- */
  async initCalendrier() {
    // Calendrier
    this.calendrier = duplicate(game.settings.get("foundryvtt-reve-de-dragon", "calendrier"));
    console.log("CALENDRIER", this.calendrier);
    if ( this.calendrier == undefined || this.calendrier.moisRdD == undefined) {
      this.calendrier.heureRdD        = 0; // Index dans heuresList
      this.calendrier.minutesRelative = 0;
      this.calendrier.moisRdD         = 0; // Index dans heuresList
      this.calendrier.jour            = 0;
      if ( game.user.isGM) { // Uniquement si GM
        game.settings.set("foundryvtt-reve-de-dragon", "calendrier", this.calendrier );
      }
    }
    // position
    this.calendrierPos = duplicate(game.settings.get("foundryvtt-reve-de-dragon", "calendrier-pos"));
    if ( this.calendrierPos == undefined || this.calendrierPos.top == undefined) {
      this.calendrierPos.top          = 200;
      this.calendrierPos.left         = 200;
      if ( game.user.isGM) { // Uniquement si GM
        game.settings.set("foundryvtt-reve-de-dragon", "calendrier-pos", this.calendrierPos );
      }
    }
    // nombre astral
    if ( game.user.isGM) {
      this.listeNombreAstral = this._loadListNombreAstral(); 
      this.rebuildListeNombreAstral(); // Ensure always up-to-date
    }
    console.log(this.calendrier, this.calendrierPos, this.listeNombreAstral);
  }
  
  /* -------------------------------------------- */
  _loadListNombreAstral() {
    return Object.values(game.settings.get("foundryvtt-reve-de-dragon", "liste-nombre-astral"));
  }

  /* -------------------------------------------- */
  static get defaultOptions() {
    const options = super.defaultOptions;
    options.template = "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html";
    options.popOut = false;
    options.resizable = false;
    return options;
  }

  /* -------------------------------------------- */
  getDateFromIndex( index ) {
    let month = Math.floor(index / 28);
    let day = (index - (month*28)) + 1;
    return day+" "+heuresList[month];
  }

  /* -------------------------------------------- */
  getCurrentHeure() {
    return heuresList[this.calendrier.heureRdD];
  }

  /* -------------------------------------------- */
  getCurrentDayIndex( ) {
    return (this.calendrier.moisRdD * 28) + this.calendrier.jour;
  }
  
  /* -------------------------------------------- */
  getJoursSuivants( num) {
    let jours = [];
    let index = this.getCurrentDayIndex();
    for (let i=0; i<num; i++) {
      jours[i] = { label: this.getDateFromIndex(index), index: index };
      index += 1;
    }
    return jours;
  }
  
  /* -------------------------------------------- */
  ajouterNombreAstral(index) {
    return {
      nombreAstral: new Roll("1d12").roll().total, 
      valeursFausses: [],
      index: index
    }
  }

  /* -------------------------------------------- */
  getCurrentNombreAstral() {
    let index = this.getCurrentDayIndex();
    return this.getNombreAstral(index);
  }

  /* -------------------------------------------- */
  getNombreAstral( index ) {
    const liste = this.listeNombreAstral || this._loadListNombreAstral();
    let astralData = liste.find( (nombreAstral, i) => nombreAstral.index == index );
    if ( astralData == undefined ) {
      this.rebuildListeNombreAstral();
      astralData = liste.find( (nombreAstral, i) => nombreAstral.index == index );
    }
    return astralData.nombreAstral || "N/A";
  }
  
  /* -------------------------------------------- */
  rebuildListeNombreAstral() {
    // Auto-create if needed
    if ( this.listeNombreAstral == undefined) 
      this.listeNombreAstral = [];

    // Nettoyage des nombres astraux anciens
    let jourCourant = this.getCurrentDayIndex();
    let jourFin = jourCourant + 12;
    let newList = this.listeNombreAstral.filter( (nombreAstral, i) =>  nombreAstral && nombreAstral.index >= jourCourant && nombreAstral.index < jourFin);
    //console.log("LSTES", this.listeNombreAstral, newList );

    let lastDay = jourCourant;
    for (let i=0; i < MAX_NOMBRE_ASTRAL; i++) {
      let nombreAstral = newList[i];
      if ( nombreAstral ) {
        lastDay = nombreAstral.index + 1;
      } else {
        newList.push(  this.ajouterNombreAstral( lastDay) );
        lastDay += 1;
      }
    }
    this.listeNombreAstral = newList;

    game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral );
  }

  /* -------------------------------------------- */
  incrementTime(minute = 0) {
    this.calendrier.minutesRelative += minute;
    if (this.calendrier.minutesRelative >= 120 ) {
      this.calendrier.minutesRelative -= 120;
      this.calendrier.heureRdD += 1;
    }
    if ( this.calendrier.heureRdD > 11 ) {
      this.calendrier.heureRdD -= 12;
      this.incrementerJour();
    }
    game.settings.set("foundryvtt-reve-de-dragon", "calendrier", duplicate(this.calendrier) );   
    // Notification aux joueurs
    game.socket.emit("system.foundryvtt-reve-de-dragon", {
      msg: "msg_sync_time",
      data: duplicate(this.calendrier)
    } );
  }
  
  /* -------------------------------------------- */
  incrementerJour( ) {
    this.calendrier.jour += 1;
    if ( this.calendrier.jour >= RDD_JOUR_PAR_MOIS) {
      this.calendrier.jour -= RDD_JOUR_PAR_MOIS;
      if ( this.calendrier.jour <= 0)
        this.calendrier.jour = 0;
      this.calendrier.moisRdD += 1;
      // Reconstruire les nombres astraux
    }
    this.rebuildListeNombreAstral();
  }

  /* -------------------------------------------- */
  syncPlayerTime( calendrier ) {
    this.calendrier = duplicate(calendrier); // Local copy update
    this.updateDisplay(); // Then update
  }

  /* -------------------------------------------- */
  positionnerHeure( indexHeure ) {
    if ( indexHeure <= this.calendrier.heureRdD ) 
      this.incrementerJour();
    this.calendrier.heureRdD = indexHeure;
    this.calendrier.minutesRelative = 0;
    game.settings.set("foundryvtt-reve-de-dragon", "calendrier",  duplicate(this.calendrier) );    
  }

  /* -------------------------------------------- */
  fillCalendrierData( data = {} ) {
    let moisKey  = heuresList[this.calendrier.moisRdD];
    let heureKey = heuresList[this.calendrier.heureRdD];

    const mois = heuresDef[moisKey];
    const heure = heuresDef[heureKey];

    //console.log(moisKey, heureKey);
    data.heureKey  = heureKey;
    data.moisKey   = moisKey;
    data.jourMois  = this.calendrier.jour + 1;
    data.nomMois   = mois.label; // heures et mois nommés identiques
    data.iconMois  = dossierIconesHeures + mois.icon;
    data.nomHeure  = heure.label;
    data.iconHeure = dossierIconesHeures + heure.icon;
    data.nomSaison = saisonsDef[mois.saison].label;
    data.minutesRelative = this.calendrier.minutesRelative;
    data.isGM            = game.user.isGM;
    return data;
  }

  /* -------------------------------------------- */
  getLectureAstrologieDifficulte( dateIndex ) {
    let indexNow = this.getCurrentDayIndex();
    let diffDay = dateIndex - indexNow;
    return - Math.floor(diffDay / 2);
  }

  /* -------------------------------------------- */
  async requestNombreAstral( request) {
    if ( game.user.isGM) { // Only GM
      console.log( request );
      let jourDiff = this.getLectureAstrologieDifficulte( request.date);
      let niveau = Number(request.astrologie.data.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);
      let rolled = await RdDResolutionTable.rollData({
        caracValue: request.carac_vue,
        finalLevel: niveau,
        showDice: false});
      let nbAstral = this.getNombreAstral( request.date );
      let nbAstralFaux = nbAstral;
      request.isValid = true;
      request.rolled  = rolled;
      if ( !rolled .isSuccess ) {
        request.isValid = false;
        while ( nbAstralFaux == nbAstral ) {
          nbAstralFaux = new Roll("1d12").roll().total;
        }
        nbAstral = nbAstralFaux;
        // Mise à jour des nombres astraux du joueur
        let astralData = this.listeNombreAstral.find( (nombreAstral, i) => nombreAstral.index == request.date );
        astralData.valeursFausses.push( {actorId: request.id, nombreAstral: nbAstralFaux});
        game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral );
      }
      request.nbAstral = nbAstral;
      if ( game.user.isGM) {
        RdDUtility.responseNombreAstral( request );
      } else  {
        game.socket.emit("system.foundryvtt-reve-de-dragon", {
          msg: "msg_response_nombre_astral",
          data: request 
        } );  
      }
    }
  }

  /* -------------------------------------------- */
  getAjustementAstrologique(heureNaissance, name='inconnu')
  {
    if (heureNaissance && heuresDef[heureNaissance]) {
      let hn = heuresDef[heureNaissance].heure;
      let chiffreAstral = this.getCurrentNombreAstral();
      let heureCourante = this.calendrier.heureRdD;
      let ecartChance = (hn + chiffreAstral - heureCourante)%12;
      switch (ecartChance)
      {
        case 0: return 4;
        case 4: case 8: return 2;
        case 6: return -4;
        case 3: case 9: return -2;
      }
    }
    else {
      ui.notifications.warn(name + " n'a pas d'heure de naissance, ou elle est incorrecte : " + heureNaissance);
    }
    return 0;
  }

  /* -------------------------------------------- */
  getData() {
    let data = super.getData();

    this.fillCalendrierData(data);

    this.setPos( this.calendrierPos );
    return data;
  }

  /* -------------------------------------------- */
  setPos(pos) {
    return new Promise(resolve => {
      function check() {
        let elmnt = document.getElementById("calendar-time-container");
        if (elmnt) {
          elmnt.style.bottom = null;
          let xPos = (pos.left) > window.innerWidth ? window.innerWidth-200 : pos.left;
          let yPos = (pos.top) > window.innerHeight-20 ? window.innerHeight-100 : pos.top;
          elmnt.style.top = (yPos) + "px";
          elmnt.style.left = (xPos) + "px";
          resolve();
        } else {
          setTimeout(check, 30);
        }
      }
      check();
    });
  }

  /* -------------------------------------------- */
  updateDisplay() { 
    let data = this.fillCalendrierData( );
     // Rebuild data
    let dateHTML = `Jour ${data.jourMois} de ${data.nomMois} (${data.nomSaison})`;
    if (game.user.isGM) {
      dateHTML = dateHTML + " - NA: "+this.getCurrentNombreAstral();
    }
    document.getElementById("calendar--move-handle").innerHTML = dateHTML;
    document.getElementById("calendar-heure-texte").innerHTML = `${data.nomHeure}`;
    document.getElementById("calendar-time").innerHTML = `${data.minutesRelative} min.`;
    document.getElementById("calendar-heure-img").src = data.iconHeure;
  }

  /* -------------------------------------------- */
  saveEditeur( calendrierData ) {    
    this.calendrier.minutesRelative = Number(calendrierData.minutesRelative);
    this.calendrier.jour            = Number(calendrierData.jourMois) - 1;
    this.calendrier.moisRdD         = heuresList.findIndex(mois => mois === calendrierData.moisKey);
    this.calendrier.heureRdD        = heuresList.findIndex(heure => heure === calendrierData.heureKey);; // Index dans heuresList
    game.settings.set("foundryvtt-reve-de-dragon", "calendrier",  duplicate(this.calendrier) );    
    
    this.rebuildListeNombreAstral();

    this.updateDisplay();
  }
  
  /* -------------------------------------------- */
  async showCalendarEditor() {    
    let calendrierData = duplicate( this.fillCalendrierData(  ) );
    if ( this.editeur == undefined ) {
      calendrierData.jourMoisOptions = Array(28).fill().map((item, index) => 1 + index);
      calendrierData.heuresOptions   = [0, 1];
      calendrierData.minutesOptions  = Array(120).fill().map((item, index) => 0 + index);
      let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html', calendrierData );
      this.editeur = new RdDCalendrierEditeur(html, this, calendrierData )
    }
    this.editeur.updateData( calendrierData );
    this.editeur.render(true);
  }

  /* -------------------------------------------- */
  async showAstrologieEditor() {
    let calendrierData  = duplicate( this.fillCalendrierData(  ) );
    let astrologieArray =  [];    
    for (let astralData of this.listeNombreAstral ) {
      astralData.humanDate = this.getDateFromIndex( astralData.index );
      for (let vf of astralData.valeursFausses) {
        let actor = game.actors.get( vf.actorId);
        console.log(vf.actorId, actor );
        vf.actorName = (actor) ? actor.name : "Inconnu";
      }
      astrologieArray.push( duplicate(astralData ) );
    }
    //console.log("ASTRO", astrologieArray);
    calendrierData.astrologieData = astrologieArray;
    let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/calendar-astrologie-template.html', calendrierData );
    let astrologieEditeur = new RdDAstrologieEditeur(html, this, calendrierData )
    astrologieEditeur.updateData( calendrierData );
    astrologieEditeur.render(true);
  }
  
  /* -------------------------------------------- */
  /** @override */
	activateListeners(html) {
    super.activateListeners(html);

    HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);

    this.updateDisplay();

    html.find('#calendar-btn-1min').click(ev => {
      ev.preventDefault();
      this.incrementTime(1);
      this.updateDisplay();
    });
    html.find('#calendar-btn-5min').click(ev => {
      ev.preventDefault();
      this.incrementTime(5);
      this.updateDisplay();
    });
    html.find('#calendar-btn-10min').click(ev => {
      ev.preventDefault();
      this.incrementTime(10);
      this.updateDisplay();
    });
    html.find('#calendar-btn-20min').click(ev => {
      ev.preventDefault();
      this.incrementTime(20);
      this.updateDisplay();
    });
    html.find('#calendar-btn-30min').click(ev => {
      ev.preventDefault();
      this.incrementTime(30);
      this.updateDisplay();
    });
    html.find('#calendar-btn-1heure').click(ev => {
      ev.preventDefault();
      this.incrementTime(120);
      this.updateDisplay();
    });
    html.find('#calendar-btn-vaisseau').click(ev => {
      ev.preventDefault();
      this.positionnerHeure(0); // 0 -> vaisseau
      this.updateDisplay();
    });
    html.find('#calendar-btn-lyre').click(ev => {
      ev.preventDefault();
      this.positionnerHeure(6); // 6 -> lyre
      this.updateDisplay();
    });
    html.find('#calendar-btn-edit').click(ev => {
      ev.preventDefault();
      this.showCalendarEditor();
    });
    html.find('#astrologie-btn-edit').click(ev => {
      ev.preventDefault();
      this.showAstrologieEditor();
    });

    html.find('#calendar--move-handle').mousedown(ev => {
      ev.preventDefault();
      ev = ev || window.event;
      let isRightMB = false;
      if ("which" in ev) { // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
        isRightMB = ev.which == 3;
      } else if ("button" in ev) { // IE, Opera 
        isRightMB = ev.button == 2;
      }

      if (!isRightMB) {
        dragElement(document.getElementById("calendar-time-container"));
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;

        function dragElement(elmnt) {
          elmnt.onmousedown = dragMouseDown;
          function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            
            document.onmouseup = closeDragElement;
            document.onmousemove = elementDrag;
          }
        
          function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            // calculate the new cursor position:
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            // set the element's new position:
            elmnt.style.bottom = null
            elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
            elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
          }
        
          function closeDragElement() {
            // stop moving when mouse button is released:
            elmnt.onmousedown = null;
            document.onmouseup = null;
            document.onmousemove = null;
            let xPos = (elmnt.offsetLeft - pos1) > window.innerWidth ? window.innerWidth-200 : (elmnt.offsetLeft - pos1);
            let yPos = (elmnt.offsetTop - pos2) > window.innerHeight-20 ? window.innerHeight-100 : (elmnt.offsetTop - pos2)
            xPos = xPos < 0 ? 0 : xPos;
            yPos = yPos < 0 ? 0 : yPos;
            if(xPos != (elmnt.offsetLeft - pos1) || yPos != (elmnt.offsetTop - pos2)){
              elmnt.style.top = (yPos) + "px";
              elmnt.style.left = (xPos) + "px";
            }
            game.system.rdd.calendrier.calendrierPos.top  = yPos; 
            game.system.rdd.calendrier.calendrierPos.left = xPos; 
            game.settings.set("foundryvtt-reve-de-dragon", "calendrier-pos",  duplicate(game.system.rdd.calendrier.calendrierPos) ); 
          }
        }
      } else if(isRightMB){
        game.system.rdd.calendrier.calendrierPos.top  = 200; 
        game.system.rdd.calendrier.calendrierPos.left = 200; 
        game.settings.set("foundryvtt-reve-de-dragon", "calendrier-pos",  duplicate(game.system.rdd.calendrier.calendrierPos) ); 
        this.setPos(game.system.rdd.calendrier.calendrierPos);
      }
    });    
  }
  
}