import { RdDItem } from "../item.js";
import { HtmlUtility } from "../html-utility.js";
import { Misc } from "../misc.js";
import { CompendiumTableHelpers } from "../settings/system-compendiums.js";
import { RdDRaretes } from "../item/raretes.js";
import { Grammar } from "../grammar.js";
import { renderTemplate } from "../constants.js";

const FILTER_GROUPS = [
  { group: "type", label: "Type d'objet" },
  { group: "comestible", label: "Alimentaire" },
  { group: "utilisation", label: "Utilisation" },
  { group: "rarete", label: "Rarete" },
  { group: "qualite", label: "Qualité" },
  { group: "enc", label: "Encombrement" },
  { group: "prix", label: "Prix" },
]

const FILTERS = [
  { group: "comestible", code: "comestible", label: "Comestible", check: (item, milieux) => item.getUtilisation() == "cuisine" },
  { group: "comestible", code: "pret", label: "Préparé", check: (item, milieux) => item.getUtilisationCuisine() == "pret" },
  { group: "comestible", code: "brut", label: "A préparer", check: (item, milieux) => item.getUtilisationCuisine() == "brut" },
  { group: "comestible", code: "boisson", label: "Boisson", check: (item, milieux) => item.isBoisson() },
  { group: "comestible", code: "alcool", label: "Alcool", check: (item, milieux) => item.isAlcool() },
  { group: "comestible", code: "immangeable", label: "Immangeable", check: (item, milieux) => item.isInventaire() && item.getUtilisation() != "cuisine" },
  { group: "utilisation", code: "alchimie", label: "Alchimique", check: (item, milieux) => item.isInventaire() && item.getUtilisation() == "alchimie" },
  { group: "utilisation", code: "soins", label: "Médical", check: (item, milieux) => item.isInventaire() && item.getUtilisation() == "soins" },
  { group: "utilisation", code: "poison", label: "Toxique", check: (item, milieux) => item.isInventaire() && item.getUtilisation() == "poison" },
  { group: "utilisation", code: "cuisine", label: "Cuisine", check: (item, milieux) => item.isInventaire() && item.getUtilisation() == "cuisine" },
  { group: "utilisation", code: "autres", label: "Autres/inconnu", check: (item, milieux) => !item.isInventaire() || item.getUtilisation() == "" },
  { group: "qualite", code: "mauvaise", label: "Mauvaise (négative)", check: (item, milieux) => item.isInventaire() && item.system.qualite < 0 },
  { group: "qualite", code: "quelconque", label: "Quelconque (0)", check: (item, milieux) => item.isInventaire() && item.system.qualite == 0 },
  { group: "qualite", code: "correcte", label: "Correcte (1-3)", check: (item, milieux) => item.isInventaire() && 1 <= item.system.qualite && item.system.qualite <= 3 },
  { group: "qualite", code: "bonne", label: "Bonne (4-6)", check: (item, milieux) => item.isInventaire() && 4 <= item.system.qualite && item.system.qualite <= 6 },
  { group: "qualite", code: "excellente", label: "Excellente (7-9)", check: (item, milieux) => item.isInventaire() && 7 <= item.system.qualite && item.system.qualite <= 9 },
  { group: "qualite", code: "mythique", label: "Mythique (10+)", check: (item, milieux) => item.isInventaire() && 10 <= item.system.qualite },
  { group: "enc", code: "negligeable", label: "Négligeable (jusqu'à 0.1)", check: (item, milieux) => item.isInventaire() && item.system.encombrement <= 0.1 },
  { group: "enc", code: "leger", label: "Léger (0.1 à 0.5)", check: (item, milieux) => item.isInventaire() && 0.1 < item.system.encombrement && item.system.encombrement <= 0.5 },
  { group: "enc", code: "moyen", label: "Moyen (0.5 à 1.5)", check: (item, milieux) => item.isInventaire() && 0.5 < item.system.encombrement && item.system.encombrement <= 1.5 },
  { group: "enc", code: "lourd", label: "Lourd (1.5 à 3)", check: (item, milieux) => item.isInventaire() && 1.5 < item.system.encombrement && item.system.encombrement <= 3 },
  { group: "enc", code: "massif", label: "Massif (3 à 10)", check: (item, milieux) => item.isInventaire() && 3 < item.system.encombrement && item.system.encombrement <= 10 },
  { group: "enc", code: "anemort", label: "Un âne mort (plus de 10)", check: (item, milieux) => item.isInventaire() && 10 < item.system.encombrement },
  { group: "prix", code: "gratuit", label: "Gratuit", check: (item, milieux) => item.isInventaire() && item.system.cout == 0 },
  { group: "prix", code: "deniers", label: "Deniers (étain)", check: (item, milieux) => item.isInventaire() && 0 < item.system.cout && item.system.cout < 0.1 },
  { group: "prix", code: "bronze", label: "Sous (bronze)", check: (item, milieux) => item.isInventaire() && 0.1 <= item.system.cout && item.system.cout < 1 },
  { group: "prix", code: "sols", label: "Sols (argent)", check: (item, milieux) => item.isInventaire() && 1 <= item.system.cout && item.system.cout < 10 },
  { group: "prix", code: "dragons", label: "Dragons (or)", check: (item, milieux) => item.isInventaire() && 10 <= item.system.cout },
]

function $filterMilieux(milieux) {
  return milieux.map(m => ({ code: m, label: m, check: (item, milieux) => item.isPresentDansMilieux(m) }))
}

function $filterRarete() {
  return RdDRaretes.raretes().filter(it => it.frequence > 0).map(r => ({
    group: "rarete",
    code: r.code,
    label: r.label,
    check: (item, milieux) => RdDRaretes.isRarete(r.code, item)
  }))
}

function $loadFilters(parameters) {
  FILTER_GROUPS.forEach(g => {
    g.filters = FILTERS.filter(f => f.group == g.group)
    g.filters.push(...$filterRarete().filter(f => f.group == g.group))
  })
}

const { HandlebarsApplicationMixin } = foundry.applications.api;
export class FenetreRechercheTirage extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) {
  static PARTS = {
    main: { template: "systems/foundryvtt-reve-de-dragon/templates/tirage/fenetre-recherche-tirage.hbs" }
  }

  static DEFAULT_OPTIONS = {
    classes: ["fenetre-recherche-tirage"],
    window: {
      title: "Recherches et tirages",
      resizable: true,
      positioned: true
    },
    position: { width: 600, height: 600 },
    dragDrop: [{ dragSelector: "a.content-link", dropSelector: "" }]
  }

  _getWindowControls() {
    if (game.user.isGM) {
      return [{ icon: "fa-solid fa-gear", label: "Configurer", action: "configurer", onclick: () => this.configurer() }]
    }
    return []
  }

  _onDragStart(event) { return true }

  static async create() {
    const milieux = await game.system.rdd.environnement.milieux()
    const parameters = {
      milieux,
      filterMilieux: $filterMilieux(milieux),
      filterGroups: foundry.utils.deepClone(FILTER_GROUPS).filter(it => it.group),
    }
    $loadFilters(parameters)
    new FenetreRechercheTirage(parameters).render({ force: true })
  }

  constructor(parameters) {
    super({})
    this.parameters = parameters
  }

  _prepareContext(options) {
    return { ...this.parameters }
  }

  _onRender(context, options) {
    super._onRender(context, options)
    this.html = $(this.element)
    this.showFilterGroup(this.html, false)
    this.html.find("a.section-filters-toggle").click(event => {
      const groupDiv = this.html.find(event.currentTarget)?.parents("div.section-filters-root").first()
      const visible = groupDiv.find("div.section-filters-content").first().is(":visible")
      this.showFilterGroup(groupDiv, !visible)
    })
    this.html.find("input:is(.activate-filter-group,.activate-filter-milieu)").change(() => this.changeListeFiltresActifs())
    this.html.find("a.supprimer-filtres").click(() => this.supprimerFiltres())
    this.html.find("a.recherche-filtres").click(() => this.recherche())
    this.html.find("a.tirage-filtres").click(async () => {
      const table = await this.buildTable()
      const row = await CompendiumTableHelpers.getRandom(table, "Item")
      await CompendiumTableHelpers.tableRowToChatMessage(row, "Item")
    })
  }

  showFilterGroup(groupDiv, show) {
    if (groupDiv) {
      HtmlUtility.showControlWhen(groupDiv.find("div.section-filters-content"), show)
      HtmlUtility.showControlWhen(groupDiv.find("i.section-filters-hide"), show)
      HtmlUtility.showControlWhen(groupDiv.find("i.section-filters-show"), !show)
    }
  }

  supprimerFiltres() {
    this.html.find("input:is(.activate-filter-group,.activate-filter-milieu)").prop("checked", false)
    this.html.find("div.liste-resultats-recherche").html("")
    this.html.find(".section-filters-text input.recherche").val("")
  }

  async recherche() {
    const table = await this.buildTable()
    const htmlResultats = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/tirage/liste-resultats-recherche.hbs", { resultats: table })
    this.html.find("div.liste-resultats-recherche").html(htmlResultats)
  }

  async buildTable() {
    const milieux = this.getSelectedMilieux()
    const filterItemMilieux = this.buildCheckedGroupFilter(milieux)
    const filter = it => filterItemMilieux(it, milieux)
    const itemFrequence = it => it.getFrequence(milieux)
    return await game.system.rdd.environnement.buildTable(itemFrequence, filter)
  }

  buildMilieuxFilter(milieux) {
    if (milieux) {
      return this.buildOrFilter(this.parameters.filterMilieux.filter(it => milieux.includes(it.code)).map(f => f.check))
    }
    return (it, mi) => true
  }

  buildFilterRechercheName() {
    const recherche = this.html.find(".section-filters-text input.recherche").val()
    if (recherche) {
      return (it, mi) => Grammar.includesLowerCaseNoAccent(it.name, recherche)
    }
    return (it, mi) => true
  }

  buildCheckedGroupFilter(milieux) {
    const filtersList = this.getGroupCheckedFilters().map(gf => this.buildOrFilter(gf.filters.map(f => f.check)))
    filtersList.push(this.buildMilieuxFilter(milieux))
    filtersList.push(this.buildFilterRechercheName())
    return this.buildAndFilter(filtersList)
  }

  buildAndFilter(filters) { return filters.reduce((f1, f2) => { return (it, mi) => f1(it, mi) && f2(it, mi) }) }
  buildOrFilter(filters) { return filters.reduce((f1, f2) => { return (it, mi) => f1(it, mi) || f2(it, mi) }) }

  changeListeFiltresActifs() {
    const milieux = this.getSelectedMilieux()
    const summariesList = this.getGroupCheckedFilters().map(gf => {
      return gf.group.label + ": " + gf.filters.map(f => f.label).reduce(Misc.joining(", "))
    })
    if (milieux) {
      summariesList.push("Milieux: " + this.parameters.filterMilieux.filter(f => milieux.includes(f.code)).map(f => f.label).reduce(Misc.joining(", ")))
    }
    const fullText = summariesList.length == 0 ? "" : summariesList.reduce(Misc.joining(" - "))
    this.html.find("span.liste-filtres-actifs").text(fullText)
  }

  getGroupCheckedFilters() {
    const checkedGroupFilters = jQuery.map(this.html.find("input.activate-filter-group:checked"), it => this.html.find(it))
      .map(element => ({ group: element.data("group"), code: element.data("code") }))
      .filter(it => it.group)
    const entries = Object.entries(Misc.classify(checkedGroupFilters, it => it.group))
    return entries.map(([key, list]) => {
      const group = this.parameters.filterGroups.find(g => g.group == key)
      const filters = list.map(it => group.filters.find(f => it.code == f.code))
      return { group, filters }
    })
  }

  getSelectedMilieux() {
    const milieux = jQuery.map(this.html.find("input.activate-filter-milieu:checked"), it => this.html.find(it).data("code"))
    return milieux.length == 0 ? undefined : milieux
  }

  async configurer() {
    FenetreRechercheConfiguration.create()
  }
}

class FenetreRechercheConfiguration extends foundry.applications.api.DialogV2 {
  static async create() {
    const configuration = {
      compendiums: game.packs.filter(it => it.metadata.type == "Item").map(it => it.metadata)
        .map(it => foundry.utils.mergeObject({ selected: game.system.rdd.environnement.compendiums.includes(it.id) }, it))
    }
    const content = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/tirage/fenetre-recherche-configuration.hbs", configuration)
    new FenetreRechercheConfiguration(content).render({ force: true })
  }

  constructor(content) {
    super({
      title: "Configuration de la recherche",
      content,
      classes: ["fenetre-recherche-configuration"],
      position: { width: 600, height: "fit-content" },
      buttons: [
        { label: "Sauvegarder", action: "sauvegarder", callback: () => this.sauvegarder() }
      ]
    })
  }

  async _onRender(context, options) {
    await super._onRender(context, options)
    this.element.querySelector("button.configuration-save")?.addEventListener("click", () => this.sauvegarder())
  }

  async sauvegarder() {
    const compendiumIds = jQuery.map(this.element.querySelectorAll("input.select-compendium:checked"), it => it.dataset.id)
    await game.system.rdd.environnement.saveCompendiums(compendiumIds)
    this.close()
  }
}
