'use client';

import { Group, Button, Popover, Menu } from '@mantine/core';
import { useRouter, useSearchParams } from 'next/navigation';
import {
  createContext,
  useContext,
  useState,
  ReactNode,
  useOptimistic,
  useTransition,
  Fragment,
} from 'react';
import { upperFirst } from '@mantine/hooks';
import { CardSortField, UrlType } from '@semble/types';
import { getUrlTypeIcon } from '@/lib/utils/icon';
import { MdFilterList } from 'react-icons/md';
import { BsGrid, BsListUl } from 'react-icons/bs';
import { CiGrid2H } from 'react-icons/ci';
import { useUserSettings } from '@/features/settings/lib/queries/useUserSettings';
import { IoMdCheckmark } from 'react-icons/io';
import { FaAsterisk } from 'react-icons/fa';

// context
interface FilterContextValue {
  router: ReturnType<typeof useRouter>;
  searchParams: ReturnType<typeof useSearchParams>;
}

const FilterContext = createContext<FilterContextValue | null>(null);

const useFilterContext = () => {
  const ctx = useContext(FilterContext);
  if (!ctx)
    throw new Error('CardFilter components must be wrapped in CardFiltersRoot');
  return ctx;
};

// root
export function CardFiltersRoot(props: { children: ReactNode }) {
  const searchParams = useSearchParams();
  const router = useRouter();

  return (
    <FilterContext.Provider
      value={{
        router,
        searchParams,
      }}
    >
      <Menu shadow="sm">
        <Menu.Target>
          <Button variant="light" color="gray" leftSection={<MdFilterList />}>
            Filters
          </Button>
        </Menu.Target>
        <Menu.Dropdown w={200}>{props.children}</Menu.Dropdown>
      </Menu>
    </FilterContext.Provider>
  );
}

// sort select
// sort select (menu-style)
export function CardFiltersSortSelect() {
  const ctx = useFilterContext();
  const [, startTransition] = useTransition();

  const sortFromUrl =
    (ctx.searchParams.get('sort') as CardSortField) ?? CardSortField.UPDATED_AT;

  const [optimisticSort, setOptimisticSort] =
    useOptimistic<CardSortField>(sortFromUrl);

  const onChange = (next: CardSortField) => {
    startTransition(() => {
      setOptimisticSort(next);

      const params = new URLSearchParams(ctx.searchParams.toString());
      params.set('sort', next);

      ctx.router.replace(`?${params.toString()}`, { scroll: false });
    });
  };

  return (
    <Fragment>
      <Menu.Label>Sort</Menu.Label>

      <Menu.Item
        onClick={() => onChange(CardSortField.UPDATED_AT)}
        rightSection={
          optimisticSort === CardSortField.UPDATED_AT && <IoMdCheckmark />
        }
        closeMenuOnClick={false}
      >
        Newest
      </Menu.Item>

      <Menu.Item
        onClick={() => onChange(CardSortField.CREATED_AT)}
        rightSection={
          optimisticSort === CardSortField.CREATED_AT && <IoMdCheckmark />
        }
        closeMenuOnClick={false}
      >
        Oldest
      </Menu.Item>

      <Menu.Item
        onClick={() => onChange(CardSortField.LIBRARY_COUNT)}
        rightSection={
          optimisticSort === CardSortField.LIBRARY_COUNT && <IoMdCheckmark />
        }
        closeMenuOnClick={false}
      >
        Most Popular
      </Menu.Item>
    </Fragment>
  );
}

// type filter
export function CardFiltersTypeFilter() {
  const ctx = useFilterContext();
  const [, startTransition] = useTransition();

  const typeFromUrl = ctx.searchParams.get('type') as UrlType | null;

  const [optimisticType, setOptimisticType] = useOptimistic<UrlType | null>(
    typeFromUrl,
  );

  const [opened, setOpened] = useState(false);

  const onChange = (type?: UrlType) => {
    const nextType = type ?? null;

    startTransition(() => {
      setOptimisticType(nextType);

      const params = new URLSearchParams(ctx.searchParams.toString());
      if (nextType) {
        params.set('type', nextType);
      } else {
        params.delete('type');
      }

      ctx.router.replace(`?${params.toString()}`, { scroll: false });
    });

    setOpened(false);
  };

  const SelectedIcon =
    optimisticType === null ? FaAsterisk : getUrlTypeIcon(optimisticType);

  return (
    <Fragment>
      <Menu.Label>Type</Menu.Label>
      <Popover opened={opened} onChange={setOpened} shadow="sm">
        <Popover.Target>
          <Menu.Item
            variant="light"
            leftSection={<SelectedIcon />}
            closeMenuOnClick={false}
            onClick={() => setOpened((o) => !o)}
          >
            {optimisticType ? upperFirst(optimisticType) : 'All Cards'}
          </Menu.Item>
        </Popover.Target>

        <Popover.Dropdown maw={300} p={'xs'}>
          <Group gap={6}>
            <Button
              size="xs"
              color="lime"
              variant={optimisticType === null ? 'filled' : 'light'}
              leftSection={<FaAsterisk />}
              onClick={() => onChange()}
            >
              All Cards
            </Button>

            {Object.values(UrlType).map((type) => {
              const Icon = getUrlTypeIcon(type);

              return (
                <Button
                  key={type}
                  size="xs"
                  color="lime"
                  variant={optimisticType === type ? 'filled' : 'light'}
                  leftSection={<Icon />}
                  onClick={() => onChange(type)}
                >
                  {upperFirst(type)}
                </Button>
              );
            })}
          </Group>
        </Popover.Dropdown>
      </Popover>
    </Fragment>
  );
}

// view toggle
// uncollected toggle
export function CardFiltersUncollectedToggle() {
  const ctx = useFilterContext();
  const [, startTransition] = useTransition();

  const uncollectedFromUrl = ctx.searchParams.get('uncollected') === 'true';

  const [optimisticUncollected, setOptimisticUncollected] =
    useOptimistic<boolean>(uncollectedFromUrl);

  const onChange = () => {
    const next = !optimisticUncollected;

    startTransition(() => {
      setOptimisticUncollected(next);

      const params = new URLSearchParams(ctx.searchParams.toString());
      if (next) {
        params.set('uncollected', 'true');
      } else {
        params.delete('uncollected');
      }

      ctx.router.replace(`?${params.toString()}`, { scroll: false });
    });
  };

  return (
    <Fragment>
      <Menu.Label>Status</Menu.Label>
      <Menu.Item
        rightSection={optimisticUncollected && <IoMdCheckmark />}
        onClick={onChange}
        closeMenuOnClick={false}
      >
        Not in collection
      </Menu.Item>
    </Fragment>
  );
}

// view toggle
export function CardFiltersViewToggle() {
  const { settings, updateSetting } = useUserSettings();

  return (
    <Fragment>
      <Menu.Label>Card View</Menu.Label>
      <Menu.Item
        leftSection={<BsGrid />}
        rightSection={settings.cardView === 'grid' && <IoMdCheckmark />}
        onClick={() => updateSetting('cardView', 'grid')}
        closeMenuOnClick={false}
      >
        Grid
      </Menu.Item>
      <Menu.Item
        leftSection={<CiGrid2H />}
        rightSection={settings.cardView === 'compact' && <IoMdCheckmark />}
        onClick={() => updateSetting('cardView', 'compact')}
        closeMenuOnClick={false}
      >
        Compact
      </Menu.Item>
      <Menu.Item
        leftSection={<BsListUl />}
        rightSection={settings.cardView === 'list' && <IoMdCheckmark />}
        onClick={() => updateSetting('cardView', 'list')}
        closeMenuOnClick={false}
      >
        List
      </Menu.Item>
    </Fragment>
  );
}

export const CardFilters = {
  Root: CardFiltersRoot,
  SortSelect: CardFiltersSortSelect,
  TypeFilter: CardFiltersTypeFilter,
  UncollectedToggle: CardFiltersUncollectedToggle,
  ViewToggle: CardFiltersViewToggle,
};
