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

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

import type { TickwerkCombatant } from '../data/documents/combatant';
export const registerDS4SpecificFunctionality = () => {
  if (CONFIG.tickwerk === undefined) CONFIG.tickwerk = {};
  foundry.utils.mergeObject(CONFIG.tickwerk, { getTiebreaker, getInitiativeFormula });

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

const getTiebreaker = async (combatant: TickwerkCombatant, combatants: TickwerkCombatant[]): Promise<number> => {
  const ds4combatant = combatant as DS4TickwerkCombatant;
  const ds4combatants = combatants as DS4TickwerkCombatant[];
  if (combatants.length === 0) return 0;

  const lowerBounds: number[] = [];
  const upperBounds: number[] = [];
  const equals: number[] = [];

  for (const combatant of ds4combatants) {
    const tiebreaker = combatant._newTiebreaker ?? combatant.getFlag(packageId, 'tiebreaker') ?? 0;
    if (getInitiative(combatant) > getInitiative(ds4combatant)) {
      lowerBounds.push(tiebreaker);
    } else if (getInitiative(combatant) < getInitiative(ds4combatant)) {
      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;
    }
  }
};

const getInitiativeFormula = (combatant: TickwerkCombatant) => {
  const started = combatant.combat?.started ?? false;
  if (!started) return '-@combatValues.initiative.total';
  const tickValue = combatant.combat?.round ?? 0;
  return `max(${tickValue} + 10 - @combatValues.initiative.total, ${tickValue})`;
};

type DS4TickwerkCombatant = TickwerkCombatant & { actor: (Actor & { data: { data: ActorData } }) | null };

const getInitiative = (combatant: DS4TickwerkCombatant): number => {
  return combatant.actor?.data.data.combatValues.initiative.total ?? -Infinity;
};

interface ActorData {
  combatValues: {
    initiative: {
      total: number;
    };
  };
}

declare global {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace Hooks {
    interface StaticCallbacks {
      'ds4.rollItem': (item: Item) => void;
    }
  }
}

const onRollItem = (item: 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,
  });
};