import { SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { CompendiumTableHelpers, CompendiumTable } from "./settings/system-compendiums.js";

const RARETES = [
  { name: 'Commune', frequence: 54, min: 27, max: 108 },
  { name: 'Frequente', frequence: 18, min: 9, max: 36 },
  { name: 'Rare', frequence: 6, min: 3, max: 12 },
  { name: 'Rarissime', frequence: 2, min: 1, max: 4 }]
const DEFAULT_RARETE = 1;

const SETTINGS_LISTE_MILIEUX = "liste-milieux";
const MILIEUX = [
  "Collines",
  "Cours d'eau",
  "Déserts",
  "Forêts",
  "Marais",
  "Maritimes",
  "Montagnes",
  "Plaines",
  "Sous-sols"
]
const ITEM_ENVIRONNEMENT_TYPES = [
  'herbe', 'ingredient', 'faune'
]

export class Environnement {

  static init() {
    game.settings.register(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX, {
      name: "Liste des milieux proposés",
      hint: "Liste des milieux proposés pour la faune&flore, séparés par des virgules",
      scope: "world",
      config: true,
      default: MILIEUX.reduce(Misc.joining(',')),
      type: String
    });
    game.system.rdd.environnement = new Environnement();
  }

  constructor() {
    this.table = new CompendiumTable('faune-flore-mineraux', 'Item', ITEM_ENVIRONNEMENT_TYPES)
  }

  static getRarete(name = undefined) {
    return RARETES.find(it => it.name == name) ?? RARETES[DEFAULT_RARETE];
  }

  static getFrequenceRarete(rarete, field = undefined) {
    const selected = this.getRarete(rarete);
    return selected[field];
  }

  async milieux() {
    return Object.values(await this.mapMilieux());
  }

  async mapMilieux() {
    const compendiumItems = await this.getElements(it => 1, it => ITEM_ENVIRONNEMENT_TYPES.includes(it.type));
    return Misc.indexLowercase(this.getMilieuxSettings().concat(Environnement.listMilieux(compendiumItems)));
  }

  static listMilieux(items) {
    return Misc.concat(items.map(it => Environnement.$itemToMilieux(it).filter(m => m)));
  }

  async autresMilieux(item) {
    const mapMilieux = await this.mapMilieux();
    const milieuxExistants = Environnement.$itemToMilieux(item).map(it => Grammar.toLowerCaseNoAccent(it));
    return Object.keys(mapMilieux)
      .filter(it => !milieuxExistants.includes(it))
      .map(it => mapMilieux[it]);
  }

  static $itemToMilieux(item) {
    return item.system.environnement.map(env => env.milieu);
  }

  getMilieuxSettings() {
    return game.settings.get(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX).split(',').map(it => it.trim()).filter(it => it != '');
  }

  async findEnvironnementsLike(search) {
    const milieux = await this.mapMilieux();
    const searchLower = Grammar.toLowerCaseNoAccent(search);
    const keys = Object.keys(milieux).filter(it => it.includes(searchLower));
    if (keys.length > 1) {
      const milieuExact = milieux[searchLower];
      if (milieuExact) {
        return [milieuExact];
      }
    }
    return keys.map(k => milieux[k]);
  }

  async searchToChatMessage(milieux, typeName) {
    const table = await this.buildEnvironnementTable(milieux);
    await CompendiumTableHelpers.tableToChatMessage(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, typeName);
    return true
  }

  async getRandom(milieux, typeName) {
    const table = await this.buildEnvironnementTable(milieux);
    return await CompendiumTableHelpers.getRandom(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, undefined, typeName);
  }

  async buildEnvironnementTable(milieux) {
    const filterMilieux = item => item.system?.environnement.filter(env => milieux.includes(env.milieu));
    const itemRareteEnMilieu = item => {
      const raretes = filterMilieux(item);
      const frequenceMax = Math.max(raretes.map(env => env.frequence));
      return raretes.find(env => env.frequence == frequenceMax);
    }
    const itemFrequenceEnMilieu = item => itemRareteEnMilieu(item)?.frequence ?? 0;
    const isPresentEnMilieu = item => itemFrequenceEnMilieu(item) > 0;
    return await this.table.buildTable(itemFrequenceEnMilieu, isPresentEnMilieu);
  }


  async getElements(itemFrequence, filter) {
    return await this.table.getContent(itemFrequence, filter);
  }
}

export class EnvironmentSheetHelper {

  static defaultOptions(defaultOptions) {
    return mergeObject(defaultOptions, {
      tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
    });
  }

  static setPosition(sheet, superPosition) {
    const position = superPosition;
    const sheetHeader = sheet.element.find(".sheet-header");
    const sheetBody = sheet.element.find(".sheet-body");
    sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
    return position;
  }

  /* -------------------------------------------- */
  static async getData(sheet, formData) {
    return mergeObject(formData, {
      milieux: await game.system.rdd.environnement.autresMilieux(sheet.item)
    });
  }

  static activateListeners(sheet) {
    if (!sheet.options.editable) return;

    sheet.html.find("input.input-selection-milieu").keypress(event => {
      if (event.keyCode == '13') {
        EnvironmentSheetHelper.onAddMilieu(sheet, event);
      }
      event.stopPropagation();
    })
    sheet.html.find("a.milieu-add").click(event => EnvironmentSheetHelper.onAddMilieu(sheet, event));
    sheet.html.find("div.environnement-milieu a.milieu-delete").click(event => EnvironmentSheetHelper.onDeleteMilieu(sheet, event));
    sheet.html.find("div.environnement-milieu select.environnement-rarete").change(event => EnvironmentSheetHelper.onChange(sheet, event,
      updated => EnvironmentSheetHelper.$changeRarete(sheet, event, updated)));
    sheet.html.find("div.environnement-milieu input[name='environnement-frequence']").change(event => EnvironmentSheetHelper.onChange(sheet, event,
      updated => EnvironmentSheetHelper.$changeFrequence(sheet, event, updated)));
  }

  static $changeFrequence(sheet, event, updated) {
    updated.frequence = Number(sheet.html.find(event.currentTarget).val());
  }

  static $changeRarete(sheet, event, updated) {
    const name = sheet.html.find(event.currentTarget).val();
    const rarete = Environnement.getRarete(name);
    updated.rarete = rarete.name;
    updated.frequence = rarete.frequence;
    // updated.frequence = Math.min(
    //   Math.max(rarete.min, updated.frequence ?? rarete.frequence),
    //   rarete.max);
  }

  static async onAddMilieu(sheet, event) {
    const milieu = sheet.html.find('input.input-selection-milieu').val();
    if (!milieu) {
      ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${sheet.item.name}`);
      return
    }
    const list = sheet.item.system.environnement;
    const exists = list.find(it => it.milieu == milieu);
    if (exists) {
      ui.notifications.warn(`${sheet.item.name} a déjà une rareté ${exists.rarete} en ${milieu} (fréquence: ${exists.frequence})`);
      return
    }
    const rarete = Environnement.getRarete();
    const newList = [...list, { milieu, rarete: rarete.name, frequence: rarete.frequence }].sort(Misc.ascending(it => it.milieu))
    await sheet.item.update({ 'system.environnement': newList })
  }

  static async onDeleteMilieu(sheet, event) {
    const milieu = EnvironmentSheetHelper.$getEventMilieu(sheet, event);
    if (milieu != undefined) {
      const newList = sheet.item.system.environnement.filter(it => it.milieu != milieu)
        .sort(Misc.ascending(it => it.milieu));
      await sheet.item.update({ 'system.environnement': newList });
    }
  }

  static async onChange(sheet, event, doMutation) {
    const list = sheet.item.system.environnement;
    const milieu = EnvironmentSheetHelper.$getEventMilieu(sheet, event);
    const updated = list.find(it => it.milieu == milieu);
    if (updated) {
      doMutation(updated);
      const newList = [...list.filter(it => it.milieu != milieu), updated]
        .sort(Misc.ascending(it => it.milieu));
      await sheet.item.update({ 'system.environnement': newList });
    }
  }

  static $getEventMilieu(sheet, event) {
    return sheet.html.find(event.currentTarget)?.parents("div.environnement-milieu").data("milieu");
  }

}