// SPDX-FileCopyrightText: 2022 Johannes Loher
//
// SPDX-License-Identifier: MIT

import { packageId } from '../constants';
import { getGame } from '../helpers';

export const registerDS4SpecificFunctionality = () => {
  if (CONFIG.tickwerk === undefined) CONFIG.tickwerk = {};
  foundry.utils.mergeObject(CONFIG.tickwerk, { getTiebreaker, getInitiativeFormula, tickTime: 0.5 });

  registerRollItemSetting();
  Hooks.on('ds4.rollItem', onRollItem);
};

/** @type {import("../data/documents/combatant").GetTiebreaker} */
const getTiebreaker = async (combatant, combatants, waiting) => {
  if (combatants.length === 0) return 0;

  /** @type {number[]} */
  const lowerBounds = [];
  /** @type {number[]} */
  const upperBounds = [];
  /** @type {number[]} */
  const equals = [];

  for (const other of combatants) {
    const tiebreaker = other._newTiebreaker ?? other.getFlag(packageId, 'tiebreaker') ?? 0;
    if (getInitiative(other) > getInitiative(combatant) || waiting === false) {
      lowerBounds.push(tiebreaker);
    } else if (getInitiative(other) < getInitiative(combatant)) {
      upperBounds.push(tiebreaker);
    } else {
      equals.push(tiebreaker);
    }
  }

  equals.sort();
  const positionAmongEquals = Math.floor(twist.random() * (equals.length + 1));

  equals.forEach((equal, index) => {
    if (index < positionAmongEquals) {
      lowerBounds.push(equal);
    } else {
      upperBounds.push(equal);
    }
  });
  const lowerBound = Math.max(...lowerBounds);
  const upperBound = Math.min(...upperBounds);

  if (lowerBound === -Infinity) {
    if (upperBound === Infinity) {
      return 0;
    } else {
      return upperBound - 1;
    }
  } else {
    if (upperBound === Infinity) {
      return lowerBound + 1;
    } else {
      return (lowerBound + upperBound) / 2;
    }
  }
};

/**
 * Get the initiative formula for a combatant.
 * @param {TickwerkCombatant} combatant The combatant for which to get the initiative formula
 * @returns {string} The initiative formula
 */
const getInitiativeFormula = (combatant) => {
  const started = combatant.combat?.started ?? false;
  if (!started) return '-@combatValues.initiative.total';
  const tickValue = combatant.combat?.tickValue ?? 0;
  return `max(${tickValue} + 10 - @combatValues.initiative.total, ${tickValue})`;
};

/**
 * Get the initiative for a combatant.
 * @param {TickwerkCombatant} combatant The combatant for which to get the initiative
 * @returns {number}
 */
const getInitiative = (combatant) => {
  return combatant.actor?.system.combatValues.initiative.total ?? -Infinity;
};

/**
 * React to an item roll by prompting the user to advance ticks.
 * @param {Item} item The item that has been rolled
 */
const onRollItem = (item) => {
  const game = getGame();
  if (game.settings.get(packageId, 'ds4.reactToRollItemHook')) {
    if (['weapon', 'spell'].includes(item.type) && item.actor?.id) {
      const combatants = item.actor
        .getActiveTokens(false, true)
        .map((token) => game.combat?.getCombatantByToken(token.id ?? ''));
      for (const combatant of combatants) {
        if (combatant?.parent?.started) combatant?.advanceTicksDialog();
      }
    }
  }
};

const registerRollItemSetting = () => {
  getGame().settings.register(packageId, 'ds4.reactToRollItemHook', {
    name: 'TICKWERK.SettingDS4ReactToRollItemHookName',
    hint: 'TICKWERK.SettingDS4ReactToRollItemHookHint',
    scope: 'client',
    config: true,
    type: Boolean,
    default: true,
  });
};
