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

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

const { HandlebarsApplicationMixin } = foundry.applications.api;
export class AppAstrologie extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
  static PARTS = {
    main: { template: "systems/foundryvtt-reve-de-dragon/templates/sommeil/app-astrologie.hbs" }
  }

  static DEFAULT_OPTIONS = {
    classes: ['rdd-calendar-astrologie'],
    window: {
      title: "Astrologie",
      controls: []
    },
    position: {
      width: 600,
      height: 600
    }
  }

  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({ force: true });
  }

  constructor(actor, options = {}) {
    super(options);
    this.actor = actor;
  }

  _prepareContext() {
    const calendrier = game.system.rdd.calendrier;
    return {
      isGM: game.user.isGM,
      isActor: this.actor != undefined,
      calendrier: calendrier.getTimestamp().toCalendrier(),
      dates: calendrier.getJoursSuivants(10).map(d => {
        d.difficulte = calendrier.getLectureAstrologieDifficulte(d.index);
        return d;
      }),
      heures: RdDTimestamp.definitions(),
      actorAstrologie: this.getActorAstrologie(),
      gmAstrologie: this.getGMAstrologie(calendrier),
      theme: {
        signeAstral: RdDTimestamp.definition(0),
        signeNaissance: RdDTimestamp.definition(0)
      }
    }
  }

  getActorAstrologie() {
    if (this.actor) {
      return {
        actor: this.actor,
        nombres: this._organizeNombresAstraux(this.actor.itemTypes['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(actor => actor.isPersonnageJoueur())
          .map(actor => this.getAjustementActor(actor, nbAstral, heures)),
        nombresAstraux: game.system.rdd.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 = foundry.utils.deepClone(nombreAstral);
    const timestamp = new RdDTimestamp({ indexDate: nombreAstral.index });
    detail.date = { mois: timestamp.mois, jour: timestamp.jour + 1 };
    detail.lectures.forEach(lecture => lecture.actorName = game.actors.get(lecture.actorId)?.getAlias() ?? "Inconnu");
    return detail;
  }

  /* -------------------------------------------- */
  _onRender(context, options) {
    super._onRender(context, options);
    this._appData = context;
    if (!this.hookReference){
      this.hookReference = Hooks.on(APP_ASTROLOGIE_REFRESH, () => this.refreshAstrologie());
    }
    this.html = $(this.element);
    this.html.find('select[name="signe-astral"]').change(event => {
      this.selectNombreAstral(event.currentTarget.value);
    })
    this.html.find('select[name="signe-naissance"]').change(event => {
      this.selectHeureNaissance(event.currentTarget.value);
    })
    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.onRebuild());
    this.html.find('[name="joursAstrologie"]').change(event => {
      const index = parseInt(event.currentTarget.value);
      const calendrier = game.system.rdd.calendrier;
      const difficulte = calendrier.getLectureAstrologieDifficulte(index);
      this.html.find('[name="date-difficulte-value"]').text(difficulte);
    });

    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 onRebuild() {
    await 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.horloge-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.horloge-roue div.disque-astro img`).css(Misc.cssRotation(angleAstrologie));

    const timestamp = game.system.rdd.calendrier.getTimestamp();

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

  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.isFirstConnectedGM()) {
      game.system.rdd.calendrier.requestNombreAstral(socketData);
    } else {
      game.socket.emit(SYSTEM_SOCKET_ID, {
        msg: "msg_request_nombre_astral",
        data: socketData
      });
    }
  }

  refreshAstrologie() {
    this.count = (this.count ?? 0)+1
    console.log(`Refreshing ${this.count}`);
    this.render({ force: true })
  }

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