import { RMFRPUtility } from "./rmfrp-utility.js";
import { RMFRP_ATTACK_TABLES } from "./rmfrp-attack-tables.js";

export class RMFRPProcessTable {

  constructor() {
    // Load a reference to the rmfrp-tables.json file
    this.rmfrpTables = RMFRP_ATTACK_TABLES
    // Loop thru the tables and create a definition object, with key, name and min/ax value of each table
    this.rmfrpTablesDef = {}

    for (let table in this.rmfrpTables) {
      let tableData = this.rmfrpTables[table]
      // Search min and max values in the tableData
      let min = Number.MAX_SAFE_INTEGER;
      let minKey = "";
      let max = Number.MIN_SAFE_INTEGER;
      let maxKey = "";
      for (let element of tableData) {
        if (Number(element.result)) {
          let value = Number(element.result)
          if (value > max) {
            max = value
            maxKey = element.result
          }
          if (value < min) {
            min = value
            minKey = element.result
          }
        } else if (element.result && element.result.includes("-")) {
          let range = element.result.split("-");
          if (Number(range[0]) > max) {
            max = Number(range[0])
            maxKey = element.result
          }
          if (Number(range[1]) < min) {
            min = Number(range[1])
            minKey = element.result
          }
        } else {
          console.error(`Element is not a number or a range`, element, table)
        }
      }

      this.rmfrpTablesDef[table] = {
        key: table,
        name: RMFRPUtility.capitalizeFirstLetters(table.replace(/_/g, " ")),
        min: min,
        minKey: minKey,
        max: max,
        maxKey: maxKey
      };
    }
    // Sort rmfrpTablesDef by name 
    this.rmfrpTablesDef = Object.values(this.rmfrpTablesDef).sort((a, b) => a.name.localeCompare(b.name))
  }

  getTableDef() {
    return this.rmfrpTablesDef;
  }

  // Get roll result from table
  getAttackRollResult(tableKey, roll, armorValue) {
    roll = Number(roll);
    if (isNaN(roll)) {
      console.error(`Roll ${roll} is not a number`)
      return undefined;
    }
    let table = this.rmfrpTables[tableKey]
    let tableDef = this.rmfrpTablesDef.find(t => t.key == tableKey)
    if (!table || !tableDef) {
      console.error(`Table ${tableKey} not found`)  
      return undefined;
    }

    // Check min and max values
    if (roll < tableDef.min) {
      // return the min value
      let elem  = table.find((element) => element.result == tableDef.minKey);
      if (elem) {
        return elem[String(armorValue)];
      } else {
        console.error(`Element ${tableDef.minKey} not found in table ${tableKey}`)
      }
    }
    if (roll > tableDef.max) {
      // return the max value
      let elem = table.find((element) => element.result == tableDef.maxKey);
      if (elem) {
        return elem[String(armorValue)];
      } else {
        console.error(`Element ${tableDef.maxKey} not found in table ${tableKey}`)
      }
    }

    return table.find((element) => {
      if (Number(element.result) ) {
        if ( Number(element.result) == Number(roll) ) {
          return element[String(armorValue)];
        }
      } else if (element.result && element.result.includes("-")) {
        // Split the result into a range
        let range = element.result.split("-");
        if (Number(roll) >= Number(range[0]) && Number(roll) <= Number(range[1])) {
          return element[String(armorValue)];
        }
      }
    });
  }

  buildFumbleNonWeaponChoices() {
    let nonWeapon = CONFIG.rmfrp.fumbles.fumble_non_weapon[0]
    let fumblesChoice = []
    for (let key in nonWeapon) {
      if (key === "score") {
        continue;
      }
      fumblesChoice.push({ key: key, name: RMFRPUtility.capitalizeFirstLetters(key) })
    }
    return fumblesChoice
  }

  buildFumbleWeaponChoices() {
    let weapon = CONFIG.rmfrp.fumbles.fumble_weapon[0]
    let fumblesChoice = []
    for (let key in weapon) {
      if (key === "score") {
        continue;
      }
      fumblesChoice.push({ key: key, name: RMFRPUtility.capitalizeFirstLetters(key) })
    }
    return fumblesChoice
  }

  getFumbleDef() {
    let fumbles = []
    for (let key in CONFIG.rmfrp.fumbles) {
      fumbles.push({ key: key, name: RMFRPUtility.capitalizeFirstLetters(key.replace(/_/g, " ")) })
    }
    return fumbles
  }

  getCriticalDef() {
    let criticals = []
    for (let key in CONFIG.rmfrp.criticals) {
      criticals.push({ key: key, name: RMFRPUtility.capitalizeFirstLetters(key.replace(/_/g, " ")) })
    }
    return criticals
  }

  async getFumbleRollResult(fumble_table, fumble_column) {
    let table = CONFIG.rmfrp.fumbles[fumble_table]
    if (!table) {
      ui.notifications.error("Fumble table not found: " + fumble_table);
      console.error(`Fumble table ${fumble_table} not found`)
      return undefined;
    }
    let roll = new Roll("1d100")
    await roll.evaluate()
    let score = roll.total
    // Search the result 
    for (let fumbleDef of table) {
      if (Number(fumbleDef.score) ) { 
        if (Number(fumbleDef.score) == score) {
          return fumbleDef[fumble_column]
        }
      } else {
        // Score is XX-YY so split it to get the range values 
        let range = fumbleDef.score.split("-")
        if (Number(range[0]) <= score && score <= Number(range[1])) {
          return fumbleDef[fumble_column]
        }
      }
    }
    return null
  }

  async getCriticalResult(tableKey, criticalKey) {
    let table = CONFIG.rmfrp.criticals[tableKey]
    if (!table) {
      console.error(`Critical table ${tableKey} not found`)
      return undefined;
    }
    let roll = new Roll("1d100")
    await roll.evaluate()
    let score = roll.total
    console.log("Critical Roll: ", score) 
    // Search the result 
    for (let criticalDef of table.criticals) {
      if (Number(criticalDef.score) ) { 
        if (Number(criticalDef.score) == score) {
          return criticalDef.levels[criticalKey.toUpperCase()]
        }
      } else {
        // Score is XX-YY so split it to get the range values 
        let range = criticalDef.score.split("-")
        if (Number(range[0]) <= score && score <= Number(range[1])) {
          return criticalDef.levels[criticalKey.toUpperCase()]
        }
      }
    }
    return null
  }

}
