import type { Accessor, ParentComponent } from 'solid-js';
import type { Document } from '../documents/documents.types';
import { safely } from '@corentinth/chisels';
import { useNavigate, useParams } from '@solidjs/router';
import { createContext, createEffect, createSignal, For, on, onCleanup, onMount, Show, useContext } from 'solid-js';
import { getDocumentIcon } from '../documents/document.models';
import { searchDocuments } from '../documents/documents.services';
import { useI18n } from '../i18n/i18n.provider';
import { cn } from '../shared/style/cn';
import { debounce } from '../shared/utils/timing';
import { useThemeStore } from '../theme/theme.store';
import { CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading } from '../ui/components/command';

const CommandPaletteContext = createContext<{
  getIsCommandPaletteOpen: Accessor<boolean>;
  openCommandPalette: () => void;
  closeCommandPalette: () => void;
}>();

export function useCommandPalette() {
  const context = useContext(CommandPaletteContext);

  if (!context) {
    throw new Error('CommandPalette context not found');
  }

  return context;
}

export const CommandPaletteProvider: ParentComponent = (props) => {
  const [getIsCommandPaletteOpen, setIsCommandPaletteOpen] = createSignal(false);
  const [getMatchingDocuments, setMatchingDocuments] = createSignal<Document[]>([]);
  const [getSearchQuery, setSearchQuery] = createSignal('');
  const [getIsLoading, setIsLoading] = createSignal(false);

  const params = useParams();
  const { t } = useI18n();

  const handleKeyDown = (e: KeyboardEvent) => {
    if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
      e.preventDefault();
      setIsCommandPaletteOpen(true);
    }
  };

  onMount(() => {
    document.addEventListener('keydown', handleKeyDown);
  });

  onCleanup(() => {
    document.removeEventListener('keydown', handleKeyDown);
  });

  const navigate = useNavigate();
  const { setColorMode } = useThemeStore();

  const searchDocs = debounce(async ({ searchQuery }: { searchQuery: string }) => {
    const [result] = await safely(searchDocuments({ searchQuery, organizationId: params.organizationId, pageIndex: 0, pageSize: 5 }));

    const { documents = [] } = result ?? {};

    setMatchingDocuments(documents);
    setIsLoading(false);
  }, 300);

  createEffect(on(
    getSearchQuery,
    (searchQuery) => {
      setMatchingDocuments([]);
      if (searchQuery.length > 1) {
        setIsLoading(true);
        searchDocs({ searchQuery });
      }
    },
  ));

  createEffect(on(
    getIsCommandPaletteOpen,
    (isCommandPaletteOpen) => {
      if (isCommandPaletteOpen) {
        setMatchingDocuments([]);
      }
    },
  ));

  const getCommandData = (): {
    label: string;
    forceMatch?: boolean;
    options: { label: string; icon: string; action: () => void; forceMatch?: boolean }[];
  }[] => [
    {
      label: t('command-palette.sections.documents'),
      forceMatch: true,
      options: getMatchingDocuments().map(document => ({
        label: document.name,
        icon: getDocumentIcon({ document }),
        action: () => navigate(`/organizations/${params.organizationId}/documents/${document.id}`),
        forceMatch: true,
      })),
    },
    {
      label: t('command-palette.sections.theme'),
      options: [
        {
          label: t('layout.theme.light'),
          icon: 'i-tabler-sun',
          action: () => setColorMode({ mode: 'light' }),
        },
        {
          label: t('layout.theme.dark'),
          icon: 'i-tabler-moon',
          action: () => setColorMode({ mode: 'dark' }),
        },
        {
          label: t('layout.theme.system'),
          icon: 'i-tabler-device-laptop',
          action: () => setColorMode({ mode: 'system' }),
        },
      ],
    },
  ];

  const onCommandSelect = ({ action }: { action: () => void }) => {
    action();
    setIsCommandPaletteOpen(false);
  };

  return (
    <CommandPaletteContext.Provider value={{
      getIsCommandPaletteOpen,
      openCommandPalette: () => setIsCommandPaletteOpen(true),
      closeCommandPalette: () => setIsCommandPaletteOpen(false),
    }}
    >

      <CommandDialog
        class="rounded-lg border shadow-md"
        open={getIsCommandPaletteOpen()}
        onOpenChange={setIsCommandPaletteOpen}
      >

        <CommandInput onValueChange={setSearchQuery} placeholder={t('command-palette.search.placeholder')} />
        <CommandList>
          <Show when={getIsLoading()}>
            <CommandLoading>
              <div class="i-tabler-loader-2 size-6 animate-spin text-muted-foreground mx-auto"></div>
            </CommandLoading>
          </Show>
          <Show when={!getIsLoading()}>
            <Show when={getMatchingDocuments().length === 0}>
              <CommandEmpty>
                {t('command-palette.no-results')}
              </CommandEmpty>
            </Show>

            <For each={getCommandData().filter(section => section.options.length > 0)}>
              {section => (
                <CommandGroup heading={section.label} forceMount={section.forceMatch ?? false}>
                  <For each={section.options}>
                    {item => (
                      <CommandItem onSelect={() => onCommandSelect(item)} forceMount={item.forceMatch ?? false}>
                        <span class={cn('mr-2 ml-2 size-4 text-primary', item.icon)} />
                        <span>{item.label}</span>
                      </CommandItem>
                    )}
                  </For>
                </CommandGroup>
              )}
            </For>
          </Show>
        </CommandList>
      </CommandDialog>

      {props.children}
    </CommandPaletteContext.Provider>
  );
};
