import "./xregexp-all.js";
import { RdDCarac } from "../rdd-carac.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDItemCompetence } from "../item-competence.js";
import { ACTOR_TYPES } from "../item.js";
import { RdDUtility } from "../rdd-utility.js";

const REGEXP_ROLL_CARAC_COMP = "(?<carac>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)(\\/(?<competence>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+))?(/(?<diff>[\\+\\-]?\\d+))?"
const XREGEXP_ROLL_CARAC_COMP = XRegExp("@roll\\[" + REGEXP_ROLL_CARAC_COMP + "\\]", 'giu')

const REGEXP_ROLL_FORMULA = "(?<formula>[^\\[\\]]+)"
const XREGEXP_ROLL_FORMULA = XRegExp("@roll\\[" + REGEXP_ROLL_FORMULA + "\\]", 'giu')

/**
 * classe pour gérer les jets de caractéristique/compétence depuis
 * les journaux/descriptions
 */
class TextRollCaracCompetence {

  static async onReplaceRoll(context) {
    const competences = await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage);
    const handler = new TextRollCaracCompetence(context.text, competences)
    context.text = await handler.replaceRollCaracCompetence()
  }

  static async onRollText(event, actor) {
   const caracCode = event.currentTarget.attributes['data-carac-code']?.value
    if (caracCode) {
      const competence = event.currentTarget.attributes['data-competence']?.value
      const diff = event.currentTarget.attributes['data-diff']?.value
      const actors = TextRollCaracCompetence.getSelectedActors(actor)
      actors.forEach(it => TextRollCaracCompetence.doRoll(it, caracCode, competence, diff))
    }
  }
  static async doRoll(actor, caracCode, competence, diff) {
    caracCode = actor.mapCarac(caracCode)
    if (competence) {
      if (actor.type == ACTOR_TYPES.personnage) {
        actor.rollCaracCompetence(caracCode, competence, diff)
      }
      else {
        actor.doRollCaracCompetence(caracCode, competence, diff)
      }
    }
    else {
      actor.rollCarac(caracCode, { diff })
    }
  }

  static getSelectedActors(actor) {
    const selected = canvas.tokens.controlled.map(it => it.actor).filter(it => it)
    if (selected.length > 0) {
      return selected
    }
    actor = actor ?? RdDUtility.getSelectedActor()
    if (actor) {
      return [actor]
    }
    return []
  }

  constructor(text, competences) {
    this.text = text
    this.competences = competences
  }

  async replaceRollCaracCompetence() {
    await XRegExp.forEach(this.text, XREGEXP_ROLL_CARAC_COMP, async (rollMatch, i) => await this._replaceOne(rollMatch, i))
    return this.text
  }

  async _replaceOne(rollMatch, i) {
    const carac = RdDCarac.caracDetails(rollMatch.carac)
    if (carac) {
      const competence = rollMatch.competence ? RdDItemCompetence.findCompetence(this.competences, rollMatch.competence) : undefined
      const replacement = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/apps/link-text-roll-carac-competence.hbs`, {
        carac: carac,
        competence: competence?.name,
        diff: rollMatch.diff
      })
      this.text = this.text.replace(rollMatch[0], replacement)
    }
  }
}

class TextRollFoundry {

  static async onReplaceRoll(context) {
    const handler = new TextRollFoundry(context.text)
    context.text = await handler.replaceRolls()
  }

  static async onRollText(event, actor) {
    const rollFoundry = event.currentTarget.attributes['data-roll-foundry']?.value
    if (rollFoundry) {
      const roll = new Roll(rollFoundry)
      await roll.evaluate()
      await roll.toMessage()
    }
  }

  constructor(text) {
    this.text = text
  }

  async replaceRolls() {
    await XRegExp.forEach(this.text, XREGEXP_ROLL_FORMULA, async (rollMatch, i) => await this._replaceOne(rollMatch, i))
    return this.text
  }

  async _replaceOne(rollMatch, i) {
    if (rollMatch.formula) {
      const replacement = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/apps/link-text-roll-foundry.hbs`, {
        formula: rollMatch.formula,
      })
      this.text = this.text.replace(rollMatch[0], replacement)
    }
  }
}


export class RdDTextEditor {

  static async enrichHTML(text, object) {
    const context = { text }
    await TextRollCaracCompetence.onReplaceRoll(context)
    await TextRollFoundry.onReplaceRoll(context)
    return await TextEditor.enrichHTML(context.text, {
      relativeTo: object,
      secrets: object?.isOwner,
      async: true
    })
  }

  static async rollText(event, actor) {
    await TextRollCaracCompetence.onRollText(event, actor)
    await TextRollFoundry.onRollText(event, actor)
  }

}