import type { CategoryName, CustomEmoji } from 'emoji-mart';

import { autoPlayGif } from '@/mastodon/initial_state';
import {
  createAppSelector,
  useAppSelector,
} from '@/mastodon/store/typed_functions';
import { createLimitedCache } from '@/mastodon/utils/cache';

import { search } from './search';
import { emojiLogger } from './utils';

const log = emojiLogger('picker');

const searchCache = createLimitedCache<LegacyEmoji[]>({ maxSize: 10, log });

type LegacyEmoji =
  | { id: string; custom?: false; native: string }
  | {
      id: string;
      custom: true;
    };

// Replicates the old legacy search function.
export async function emojiMartSearch({
  token,
  locale,
  limit = 5,
  signal,
}: {
  token: string;
  locale: string;
  limit?: number;
  signal?: AbortSignal;
}): Promise<LegacyEmoji[] | null> {
  try {
    const query = token.replace(':', '').trim();
    if (!query.length) {
      return [];
    }

    const cacheKey = `${query}|${locale}|${limit}`;
    const cachedResult = searchCache.get(cacheKey);
    if (cachedResult) {
      return cachedResult;
    }

    const results = await search({
      query,
      locale,
      limit,
      signal,
    });
    const legacyResults = results.map((emoji) =>
      'shortcode' in emoji
        ? ({ id: emoji.shortcode, custom: true } as const)
        : {
            id: emoji.label.replaceAll(' ', '_').toLowerCase(),
            native: emoji.unicode,
          },
    );
    searchCache.set(cacheKey, legacyResults);

    return legacyResults;
  } catch {
    log('aborted search for "%s"', token);
    return null;
  }
}

const defaultCategories = [
  'people',
  'nature',
  'foods',
  'activity',
  'places',
  'objects',
  'symbols',
  'flags',
] as CategoryName[];

const selectPickerData = createAppSelector(
  [(state) => state.emojis.custom, (state) => state.emojis.customCategories],
  (emojis, categories) => {
    // Create a map of shortcode to category name.
    const categoryMap = new Map<string, string>();
    for (const category in categories) {
      const catEmojis = categories[category];
      if (!catEmojis?.length) {
        continue;
      }
      for (const shortcode of catEmojis) {
        categoryMap.set(shortcode, category);
      }
    }

    const customEmojis: CustomEmoji[] = [];
    for (const shortcode in emojis) {
      const emoji = emojis[shortcode];
      if (!emoji) {
        continue;
      }

      customEmojis.push({
        name: shortcode,
        id: shortcode,
        custom: true,
        short_names: [shortcode],
        imageUrl: autoPlayGif ? emoji.url : emoji.static_url,
        customCategory: categoryMap.get(shortcode),
      } as CustomEmoji);
    }

    searchCache.clear();
    log('regenerated the picker data');

    return {
      emojis: customEmojis,
      categories: [
        'recent',
        'custom',
        ...Object.keys(categories)
          .toSorted()
          .map((category) => `custom-${category}`),
        ...defaultCategories,
      ] as CategoryName[],
    };
  },
);

export function usePickerEmojis() {
  return useAppSelector(selectPickerData);
}
