import { ColorSchemeName } from '@preply/ds-core';
import {
    ColorSchemeInterface,
    ColorSchemeProvider,
    ThemeInterface,
    useTheme,
    useThemes,
} from '@preply/ds-web-core';
// eslint-disable-next-line no-restricted-imports
import { getToken } from '@preply/ds-web-core/dist/token/private/getToken';
import React, { FC, createContext, useCallback, useEffect, useState } from 'react';

import { FLAT_TOKENS } from '../constants/token-values-flattened';
import { filterTokens } from '../functions/token.filter';
import { ExtendedToken } from '../types';

export interface TokenSearchContextShape {
    terms?: string;
    colorScheme?: ColorSchemeName;
    results: ExtendedToken[];
    setColorScheme: (colorScheme: ColorSchemeName) => void;
    setSearchTerms: (terms: string) => void;
}

export const TokenSearchContext = createContext<TokenSearchContextShape>({
    terms: '',
    colorScheme: undefined,
    results: [],
    setColorScheme: () => undefined,
    setSearchTerms: () => undefined,
});

const initialColorScheme =
    (window?.localStorage?.getItem('storybook.ds-color-scheme') as ColorSchemeName) || undefined;

export function flattenTokens(theme: ThemeInterface, colorScheme: ColorSchemeInterface) {
    const tokens = FLAT_TOKENS.map(t => ({
        ...t,
        value: `${getToken(theme, colorScheme, t.token)}`,
    }));

    return tokens;
}

export const TokenSearchProvider: FC = ({ children }) => {
    const { findColorScheme } = useThemes();
    const { theme } = useTheme();
    const [colorScheme, setScheme] = useState<ColorSchemeName | undefined>(initialColorScheme);
    const [terms, setTerms] = useState<string | undefined>('');
    const [results, setResults] = useState<ExtendedToken[]>([]);

    const setColorScheme = useCallback((s: ColorSchemeName) => setScheme(s), [setScheme]);
    const setSearchTerms = useCallback((t: string) => setTerms(t), [setTerms]);

    if (!theme) {
        throw new Error('useToken() must be used within a ThemeProvider');
    }

    useEffect(() => {
        const currentColorScheme = findColorScheme(colorScheme || 'base');

        const tokens = flattenTokens(theme, currentColorScheme);

        setResults(filterTokens(tokens, terms, !!colorScheme));
    }, [colorScheme, findColorScheme, terms, theme]);

    return (
        <TokenSearchContext.Provider
            value={{ terms, results, colorScheme, setSearchTerms, setColorScheme }}
        >
            <ColorSchemeProvider colorScheme={colorScheme || 'base'}>
                {children}
            </ColorSchemeProvider>
        </TokenSearchContext.Provider>
    );
};
