import { SYSTEM_RDD } from "../constants.js";
import { Misc } from "../misc.js";
import { RDD_MINUTES_PAR_HEURES, RDD_MINUTES_PAR_JOUR, RdDTimestamp } from "../rdd-timestamp.js";

export const APP_ASTROLOGIE_REFRESH = `${SYSTEM_RDD}-refresh-astrologie`

export class AppAstrologie extends Application {
  static async create(actor = undefined, options = {}) {
    if (actor == undefined && !game.user.isGM) {
      actor = game.user.character
    }
    if (!actor && !game.user.isGM) {
      console.error("AppAstrologie uniquement accessible pour le MJ, ou depuis un personnage pour un joueur")
    }
    new AppAstrologie(actor, options).render(true);
  }


  static get defaultOptions() {
    return mergeObject(super.defaultOptions, {
      template: "systems/foundryvtt-reve-de-dragon/templates/sommeil/app-astrologie.hbs",
      title: "Astrologie",
      width: 'fit-content',
      height: 'fit-content',
      popOut: true,
      resizable: false
    });
  }

  constructor(actor, options = {}) {
    super(options);
    this.actor = actor;
    this.hookReference = Hooks.on(APP_ASTROLOGIE_REFRESH, () => this.refreshAstrologie());
  }

  getData(options) {
    this.appData = super.getData(options)
    const calendrier = game.system.rdd.calendrier;
    mergeObject(this.appData, {
      isGM: game.user.isGM,
      isActor: this.actor != undefined,
      calendrier: calendrier.getTimestamp().toCalendrier(),
      dates: calendrier.getJoursSuivants(10),
      heures: RdDTimestamp.definitions(),
      actorAstrologie: this.getActorAstrologie(),
      gmAstrologie: this.getGMAstrologie(calendrier),
      theme: {
        signeAstral: RdDTimestamp.definition(0),
        signeNaissance: RdDTimestamp.definition(0)
      }
    })
    return this.appData;
  }

  getActorAstrologie() {
    if (this.actor) {
      return {
        actor: this.actor,
        nombres: this._organizeNombresAstraux(this.actor.listItems('nombreastral')),
        ajustements: CONFIG.RDD.difficultesLibres,
        etat: this.actor.getEtatGeneral(),
        astrologie: this.actor.getCompetence('Astrologie')
      }
    }
    return {}
  }

  _organizeNombresAstraux(nombresAstraux) {
    let organized = {};
    nombresAstraux.forEach(na => {
      if (!organized[na.system.jourindex]) {
        organized[na.system.jourindex] = {
          listValues: [],
          jourlabel: na.system.jourlabel
        }
      }
      organized[na.system.jourindex].listValues.push(na.system.value);
    })
    return organized;
  }

  getGMAstrologie(calendrier) {
    if (game.user.isGM) {
      const nbAstral = calendrier.getNombreAstral()
      const heures = RdDTimestamp.heures();
      return {
        ajustementsActors: game.actors.filter(it => it.isPersonnage() && it.hasPlayerOwner)
          .map(actor => this.getAjustementActor(actor, nbAstral, heures)),
        nombresAstraux: calendrier.getNombresAstraux().map(na => this.getDetailNombreAstral(na))
      }
    }
    return {}
  }

  getAjustementActor(actor, nbAstral, heures) {
    const hn = RdDTimestamp.findHeure(actor.getHeureNaissance())?.heure ?? 0;
    return {
      actor,
      ajustements: heures.map(heure => {
        return { heure, ajustement: RdDTimestamp.ajustementAstrologiqueHeure(hn, nbAstral, heure) };
      })
    }
  }

  getDetailNombreAstral(nombreAstral) {
    const detail = duplicate(nombreAstral);
    const timestamp = new RdDTimestamp({ indexDate: nombreAstral.index });
    detail.date = { mois: timestamp.mois, jour: timestamp.jour + 1 };
    detail.valeursFausses.forEach(fausse => fausse.actorName = game.actors.get(fausse.actorId).name ?? "Inconnu");
    return detail;
  }

  /* -------------------------------------------- */
  activateListeners(html) {
    super.activateListeners(html);
    this.html = html;
    this.html.find('select[name="signe-astral"]').change(event => {
      this.selectNombreAstral(this.html.find('select[name="signe-astral"]').val());
    })
    this.html.find('select[name="signe-naissance"]').change(event => {
      this.selectHeureNaissance(this.html.find('select[name="signe-naissance"]').val());
    })
    this.html.find('td.nombre-astral').click(event => {
      this.selectNombreAstral(Number.parseInt(event.currentTarget.attributes['data-nombre-astral'].value) - 1);
    })
    this.html.find('tr.heure-naissance').click(event => {
      this.selectHeureNaissance(event.currentTarget.attributes['data-heure-naissance'].value);
    })
    this.html.find('[name="jet-astrologie"]').click(event => this.requestJetAstrologie());
    this.html.find('[name="rebuild-nombres-astraux"]').click(event => this.rebuildNombresAstraux());

    this.onCalculThemeAstral();
  }

  selectHeureNaissance(heureNaissance) {
    this.appData.theme.signeNaissance = RdDTimestamp.definition(heureNaissance);
    this.onCalculThemeAstral();
  }

  selectNombreAstral(nombreAstral) {
    this.appData.theme.signeAstral = RdDTimestamp.definition(nombreAstral);
    this.onCalculThemeAstral();
  }

  /* -------------------------------------------- */
  async rebuildNombresAstraux() {
    game.system.rdd.calendrier.resetNombresAstraux();

    await game.system.rdd.calendrier.rebuildNombresAstraux();
  }

  onCalculThemeAstral() {
    const chiffreAstral = this.appData.theme.signeAstral.heure + 1;
    const heureNaissance = this.appData.theme.signeNaissance.heure + 1;
    RdDTimestamp.definitions().forEach(dh => {
      const ajustement = RdDTimestamp.ajustementAstrologiqueHeure(heureNaissance, chiffreAstral, dh.heure + 1);
      const txtAjustement = ajustement == 0 ? '' : Misc.toSignedString(ajustement);
      this.html.find(`div.astro-ajustement.heure-${dh.hh}`).text(txtAjustement)
    });

    this.html.find(`select[name="signe-astral"]`).val(this.appData.theme.signeAstral.key)
    this.html.find(`select[name="signe-naissance"]`).val(this.appData.theme.signeNaissance.key)

    const angleAstrologie = ((chiffreAstral + heureNaissance) * 30) % 360 - 45;
    this.html.find(`div.astro-roue div.astro-disque img`).css(this.cssRotation(angleAstrologie));
    
    const timestamp = game.system.rdd.calendrier.getTimestamp();

    this.html.find(`div.astro-roue div.astro-horloge-heure img`).css(this.cssRotation(timestamp.angleHeure));
    this.html.find(`div.astro-roue div.astro-horloge-minute img`).css(this.cssRotation(timestamp.angleMinute));
  }

  cssRotation(angleAstrologie) {
    const rotation = `rotate(${angleAstrologie}deg)`;
    return {
      'transform': rotation,
      '-ms-transform': rotation,
      '-moz-transform': rotation,
      '-webkit-transform': rotation,
      '-o-transform': rotation
    };
  }

  requestJetAstrologie() {
    if (!this.appData?.isActor) {
      return
    }
    let socketData = {
      id: this.appData.actorAstrologie.actor.id,
      carac_vue: this.actor.system.carac['vue'].value,
      etat: this.actor.getEtatGeneral(),
      astrologie: this.actor.getCompetence('Astrologie'),
      conditions: this.html.find('[name="diffConditions"]').val(),
      date: this.html.find('[name="joursAstrologie"]').val(),
      userId: game.user.id
    }
    if (Misc.isUniqueConnectedGM()) {
      game.system.rdd.calendrier.requestNombreAstral(socketData);
    } else {
      game.socket.emit(SYSTEM_SOCKET_ID, {
        msg: "msg_request_nombre_astral",
        data: socketData
      });
    }
  }

  refreshAstrologie() {
    this.render(true)
  }

  async close(options) {
    Hooks.off(APP_ASTROLOGIE_REFRESH, this.hookReference);
    this.hookReference = undefined
    await super.close(options)
  }
}