import { selector, selectorFamily } from "recoil";
import TinyColor from "tinycolor2";
import Fuse from "fuse.js";

import { searchQueryAtom, iconColorAtom } from "./atoms";
import { IconEntry, IconCategory } from "../lib";
import { icons } from "../lib/icons";

const fuse = new Fuse(icons, {
  keys: [{ name: "name", weight: 2 }, "tags", "categories"],
  threshold: 0.2, // Tweak this to what feels like the right number of results
  // shouldSort: false, // We may want to sort if we find too many results?
});

export const filteredQueryResultsSelector = selector<Readonly<IconEntry[]>>({
  key: "filteredQueryResultsSelector",
  get: ({ get }) => {
    const query = get(searchQueryAtom).trim().toLowerCase();
    if (!query) return icons;

    return new Promise((resolve) =>
      resolve(fuse.search(query).map((value) => value.item))
    );
  },
});

type CategorizedIcons = Partial<Record<IconCategory, IconEntry[]>>;

export const categorizedQueryResultsSelector = selector<
  Readonly<CategorizedIcons>
>({
  key: "categorizedQueryResultsSelector",
  get: ({ get }) => {
    const filteredResults = get(filteredQueryResultsSelector);
    return new Promise((resolve) =>
      resolve(
        filteredResults.reduce<CategorizedIcons>((acc, curr) => {
          curr.categories.forEach((category) => {
            if (!acc[category]) acc[category] = [];
            acc[category]!!.push(curr);
          });
          return acc;
        }, {})
      )
    );
  },
});

export const singleCategoryQueryResultsSelector = selectorFamily<
  Readonly<IconEntry[]>,
  IconCategory
>({
  key: "singleCategoryQueryResultsSelector",
  get: (category: IconCategory) => ({ get }) => {
    const filteredResults = get(filteredQueryResultsSelector);
    return new Promise((resolve) =>
      resolve(
        filteredResults.filter((icon) => icon.categories.includes(category))
      )
    );
  },
});

export const isDarkThemeSelector = selector<boolean>({
  key: "isDarkThemeSelector",
  get: ({ get }) => TinyColor(get(iconColorAtom)).isLight(),
});
