import { Room } from 'matrix-js-sdk';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { IPowerLevels } from './usePowerLevels';
import { useStateEvent } from './useStateEvent';
import { MemberPowerTag, StateEvent } from '../../types/matrix/room';

export type PowerLevelTags = Record<number, MemberPowerTag>;

const powerSortFn = (a: number, b: number) => b - a;
const sortPowers = (powers: number[]): number[] => powers.sort(powerSortFn);

export const getPowers = (tags: PowerLevelTags): number[] => {
  const powers: number[] = Object.keys(tags)
    .map((p) => parseInt(p, 10))
    .filter((power): power is number => !Number.isNaN(power));

  return sortPowers(powers);
};

export const getUsedPowers = (powerLevels: IPowerLevels): Set<number> => {
  const powers: Set<number> = new Set();

  const findAndAddPower = (data: Record<string, unknown>) => {
    Object.keys(data).forEach((key) => {
      const powerOrAny: unknown = data[key];

      if (typeof powerOrAny === 'number') {
        powers.add(powerOrAny);
        return;
      }
      if (powerOrAny && typeof powerOrAny === 'object') {
        findAndAddPower(powerOrAny as Record<string, unknown>);
      }
    });
  };

  findAndAddPower(powerLevels);

  return powers;
};

type TFunction = (key: string) => string;

const getDefaultTags = (t: TFunction): PowerLevelTags => ({
  9001: {
    name: t('RoomSettings.power_goku'),
    color: '#ff6a00',
  },
  150: {
    name: t('RoomSettings.power_manager'),
    color: '#ff6a7f',
  },
  101: {
    name: t('RoomSettings.power_founder'),
    color: '#0000ff',
  },
  100: {
    name: t('RoomSettings.power_admin'),
    color: '#0088ff',
  },
  50: {
    name: t('RoomSettings.power_moderator'),
    color: '#1fd81f',
  },
  0: {
    name: t('RoomSettings.power_member'),
    color: '#91cfdf',
  },
  [-1]: {
    name: t('RoomSettings.power_muted'),
    color: '#888888',
  },
});

const generateFallbackTag = (
  powerLevelTags: PowerLevelTags,
  power: number,
  t: TFunction
): MemberPowerTag => {
  const highToLow = sortPowers(getPowers(powerLevelTags));

  const tagPower = highToLow.find((p) => p < power);
  const tag = typeof tagPower === 'number' ? powerLevelTags[tagPower] : undefined;

  return {
    name: tag ? `${tag.name} ${power}` : `${t('RoomSettings.power_team')} ${power}`,
  };
};

const LEGACY_CINNY_POWER_LEVEL_TAGS = 'in.cinny.room.power_level_tags' as StateEvent;

export const usePowerLevelTags = (room: Room, powerLevels: IPowerLevels): PowerLevelTags => {
  const { t } = useTranslation();
  const tagsEvent = useStateEvent(room, StateEvent.PowerLevelTags);
  const legacyTagsEvent = useStateEvent(room, LEGACY_CINNY_POWER_LEVEL_TAGS);
  const activeTagsEvent = tagsEvent ?? legacyTagsEvent;

  const powerLevelTags: PowerLevelTags = useMemo(() => {
    const defaultTags = getDefaultTags(t);
    const content = activeTagsEvent?.getContent<PowerLevelTags>();
    const powerToTags: PowerLevelTags = { ...content };

    const powers = getUsedPowers(powerLevels);
    Array.from(powers).forEach((power) => {
      if (powerToTags[power]?.name === undefined) {
        powerToTags[power] = defaultTags[power] ?? generateFallbackTag(defaultTags, power, t);
      }
    });

    return powerToTags;
  }, [powerLevels, activeTagsEvent, t]);

  return powerLevelTags;
};

const generateFallbackTagSimple = (
  powerLevelTags: PowerLevelTags,
  power: number
): MemberPowerTag => {
  const highToLow = sortPowers(getPowers(powerLevelTags));

  const tagPower = highToLow.find((p) => p < power);
  const tag = typeof tagPower === 'number' ? powerLevelTags[tagPower] : undefined;

  return {
    name: tag ? `${tag.name} ${power}` : `#${power}`,
  };
};

export const getPowerLevelTag = (
  powerLevelTags: PowerLevelTags,
  powerLevel: number
): MemberPowerTag => {
  const tag: MemberPowerTag | undefined = powerLevelTags[powerLevel];
  return tag ?? generateFallbackTagSimple(powerLevelTags, powerLevel);
};
