import React, { Fragment, useCallback, useEffect, useState } from 'react';
import { SilkeBox } from '../silke-box';
import { SilkeButton } from '../silke-button';
import ButtonContext from '../silke-button/context';
import { SilkeSearchField } from '../silke-search-field';
import { SilkeText } from '../silke-text';
import { SilkeToolbar } from '../silke-toolbar';
import { SilkeVirtualGrid } from '../silke-virtual';
import { TabProps } from './utils';
import styles from './styles.scss';

type EmojiCategory = {
  id: string;
  name: string;
  emojis: string[];
};

type Emoji = {
  a: string;
  b: string;
  j?: string[];
  k: number[];
  m?: string;
  o: number;
};

function toEmoji(unified: string): string {
  const unicodes = unified.split('-'),
    codePoints = unicodes.map((u) => Number(`0x${u}`));

  return String.fromCodePoint(...codePoints);
}

type EmojiData = {
  compressed: true;
  categories: EmojiCategory[];
  emojis: Record<string, Emoji>;
  aliases: Record<string, string>;
};

let emojiPromise: Promise<EmojiData>;

async function fetchEmojis(): Promise<EmojiData> {
  if (!emojiPromise) {
    emojiPromise = fetch('https://cdn.vev.design/icons/emojis.json').then((r) => r.json());
  }
  return emojiPromise;
}

export default function EmojiTab({ onSelect }: TabProps) {
  const [emojis, setEmojis] = useState<EmojiData | null>(null);
  const [query, setQuery] = useState('');
  useEffect(() => {
    fetchEmojis().then(setEmojis);
  }, []);

  const filtered = React.useMemo<EmojiCategory[]>(() => {
    if (!emojis) return [];
    if (query.length === 0) return emojis.categories;

    const lowercaseQuery = query.toLocaleLowerCase();

    const result = emojis.categories
      .map((category) => {
        return {
          ...category,
          emojis: category.emojis.filter((id) => {
            if (id.includes(lowercaseQuery)) {
              return true;
            }

            const emoji = emojis.emojis[id];
            if (emoji.a.includes(lowercaseQuery)) {
              return true;
            }

            return emoji.j && emoji.j.find((keyword) => keyword.includes(lowercaseQuery));
          }),
        };
      })
      .filter((category) => category.emojis.length > 0);

    return result;
  }, [query, emojis]);

  const handleRandom = useCallback(() => {
    if (emojis) {
      const randomCategoryIndex = Math.floor(Math.random() * filtered.length);
      const randomEmojiIndex = Math.floor(
        Math.random() * filtered[randomCategoryIndex].emojis.length,
      );
      const emoji = emojis.emojis[filtered[randomCategoryIndex].emojis[randomEmojiIndex]];
      onSelect({ type: 0, value: toEmoji(emoji.b) });
    }
  }, [emojis, filtered, onSelect]);

  return (
    <ButtonContext size="base" kind="ghost">
      <SilkeToolbar size="base">
        <SilkeSearchField
          placeholder="Search emoji..."
          autoFocus
          flex
          size="base"
          search={query}
          onChange={setQuery}
          onReset={() => setQuery('')}
        />
        <SilkeButton icon="random" onClick={handleRandom} />
      </SilkeToolbar>
      <SilkeBox column gap="s" pad="m" flex scroll>
        {!emojis && (
          <SilkeBox gap="xxs">
            <SilkeButton icon="history" loading />
            <SilkeButton icon="history" loading />
            <SilkeButton icon="history" loading />
          </SilkeBox>
        )}
        {filtered.map((category) => (
          <Fragment key={category.id}>
            <SilkeText tag="small" color="neutral-80">
              {category.name}
            </SilkeText>

            <SilkeVirtualGrid
              items={category.emojis}
              cell={[32, 32]}
              style={{
                fontFamily:
                  '"Segoe UI Emoji", "Segoe UI Symbol", "Segoe UI", "Apple Color Emoji", "Twemoji Mozilla", "Noto Color Emoji", "Android Emoji"',
              }}
            >
              {(emoji) => {
                const value = emojis?.emojis[emoji]?.b;
                if (!value) return false;
                return (
                  <SilkeButton
                    className={styles.emojiButton}
                    key={emoji}
                    icon={toEmoji(value) as any}
                    onClick={() => onSelect({ type: 0, value: toEmoji(value) })}
                  />
                );
              }}
            </SilkeVirtualGrid>
          </Fragment>
        ))}
      </SilkeBox>
    </ButtonContext>
  );
}
