import React, { createContext, useContext, useCallback, useMemo } from 'react';

import { useLocalState } from '../hooks/use-local-state';

export const CODE_GROUP_SNIPPET_NAME_KEY = 'redocly:codeGroupSnippetName';

type CodeSnippetContextType = {
  activeSnippets: Record<string, string>;
  setActiveSnippet: (groupId: string, snippetId: string) => void;
};

export const CodeSnippetContext = createContext<CodeSnippetContextType | null>(null);

export function CodeSnippetProvider({ children }: { children: React.ReactNode }) {
  const [activeSnippets, setActiveSnippets] = useLocalState<Record<string, string>>(
    CODE_GROUP_SNIPPET_NAME_KEY,
    {},
  );

  const setActiveSnippet = useCallback(
    (groupId: string, snippetId: string) => {
      setActiveSnippets({ ...activeSnippets, [groupId]: snippetId });
    },
    [activeSnippets, setActiveSnippets],
  );

  const contextValue = { activeSnippets, setActiveSnippet };

  return <CodeSnippetContext.Provider value={contextValue}>{children}</CodeSnippetContext.Provider>;
}

export const useCodeSnippetContext = (): CodeSnippetContextType => {
  const context = useContext(CodeSnippetContext);

  if (!context) {
    throw new Error('useCodeSnippetContext must be used within a CodeSnippetContext');
  }

  return context;
};

export const useActiveCodeSnippetId = (
  groupId?: string,
  availableSnippets?: { id: string }[],
): [string, (id: string) => void] => {
  const { activeSnippets, setActiveSnippet } = useCodeSnippetContext();

  const storedSnippetId = groupId ? activeSnippets[groupId] || '' : '';

  const activeId = useMemo(() => {
    if (!availableSnippets?.length) return storedSnippetId;

    const found = storedSnippetId && availableSnippets.find((s) => s.id === storedSnippetId);
    return found ? storedSnippetId : availableSnippets[0]?.id || '';
  }, [storedSnippetId, availableSnippets]);

  const setActiveSnippetId = useCallback(
    (id: string) => {
      if (groupId) {
        setActiveSnippet(groupId, id);
      }
    },
    [groupId, setActiveSnippet],
  );

  return [activeId, setActiveSnippetId];
};
