import { type CalcdexPokemon, type CalcdexPlayerKey } from '@showdex/interfaces/calc';
import { getAuthUsername } from '@showdex/utils/host';
import { detectPokemonIdent } from './detectPokemonIdent';

/**
 * Attempts to detect the player key from the `ident` of the passed-in `pokemon`.
 *
 * @since 0.1.0
 */
export const detectPlayerKeyFromPokemon = <
  TPokemon extends Partial<Showdown.PokemonDetails>,
>(
  pokemon: TPokemon,
): CalcdexPlayerKey => {
  if ((pokemon as CalcdexPokemon)?.playerKey) {
    return (pokemon as CalcdexPokemon).playerKey;
  }

  const ident = detectPokemonIdent(pokemon);

  if (!ident) {
    return null;
  }

  return /^(p\d)[a-z]?:/.exec(ident)?.[1] as CalcdexPlayerKey;
};

/**
 * Attempts to detect the player key of the ~~logged-in~~ authenticated user from the passed-in `battle`.
 *
 * * As of v1.3.0, this will now **first** check through `battle.myPokemon[]` via `detectPlayerKeyFromPokemon()`
 *   (since we'd only have that info as the authenticated player [who's not necessarily registered; i.e., a named guest])
 *   & then do what this used to do pre-v1.3.0, i.e.:
 *   - If no user is logged in, `null` will be returned.
 *   - If the logged-in user is not a player in the battle, `null` will also be returned.
 *
 * @since 1.0.2
 */
export const detectAuthPlayerKeyFromBattle = (
  battle: Partial<Showdown.Battle>,
): CalcdexPlayerKey => {
  const detectedPlayerKey = detectPlayerKeyFromPokemon(battle?.myPokemon?.[0]);

  if (detectedPlayerKey) {
    return detectedPlayerKey;
  }

  const authName = getAuthUsername();

  if (!authName) {
    return null;
  }

  return battle?.sides?.find?.((s) => 'name' in (s || {}) && [
    s.id,
    s.name,
  ].filter(Boolean).includes(authName))?.sideid || null;
};

/**
 * Attempts to detect the player key from the passed-in `battle`.
 *
 * * If a user is logged in and is also a player in the battle, their corresponding `sideid`
 *   will be returned as the player key.
 *   - Opponent key can be determined from the opposite side, i.e., if the player key is `'p1'`,
 *     then the opponent key is `'p2'`, and vice versa.
 *
 * @since 0.1.0
 */
export const detectPlayerKeyFromBattle = (
  battle: Partial<Showdown.Battle>,
): CalcdexPlayerKey => {
  // check if the logged in user is a player in the battle
  const authKey = detectAuthPlayerKeyFromBattle(battle);

  if (authKey) {
    return authKey;
  }

  const {
    myPokemon,
    mySide,
  } = battle || {};

  if (mySide?.sideid) {
    return mySide.sideid;
  }

  const [firstPokemon] = myPokemon || [];

  if (!firstPokemon) {
    return null;
  }

  return detectPlayerKeyFromPokemon(firstPokemon);
};
