import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React from 'react';
import PlaygroundSettings from './components/PlaygroundSettings';
import { ModelProvider, useModelContext } from './contexts/ModelContext';
import { McpServersProvider, useMcpServers } from './contexts/McpContext';
import { ChatSettingsProvider } from './contexts/ChatSettingsContext';
import { ChatProvider } from './contexts/ChatContext';
import { ChatSessionsProvider } from './contexts/ChatSessionsContext';
import { ChatDialog } from './components/ChatDialog';
import { SlashCommandPromptProvider } from './contexts/SlashCommandPromptContext';
import { CustomPromptsProvider } from './contexts/customPrompts/useCustomPrompts';
import { AdditionalToolsProvider } from './contexts/AdditionalToolsContext';
import { ThemeProvider, useTheme, createTheme, defaultTheme, darkTheme, systemTheme } from './theme';
import { StorageAdapterProvider } from './contexts/StorageAdapterContext';
import { registerProviderPlugin } from './lib/providers';
import { ProviderRegistryProvider, useProviderRegistry } from './contexts/ProviderRegistryContext';
import { CredentialSyncProvider } from './contexts/CredentialContext';
import { coerceStoredModels } from './lib/credentialUtils';
const sanitizeIdSegment = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
const buildInitialServerEntries = (servers) => {
    if (!servers?.length) {
        return undefined;
    }
    const entries = [];
    const urlToId = new Map();
    const idInUse = new Set();
    let generatedCount = 0;
    const upsertEntry = (id, options) => {
        const existingIndex = entries.findIndex((entry) => entry.id === id);
        if (existingIndex >= 0) {
            entries[existingIndex] = { id, options };
        }
        else {
            entries.push({ id, options });
        }
        idInUse.add(id);
    };
    servers.forEach((server, index) => {
        if (server && typeof server.id === 'string' && server.options) {
            const entry = server;
            const trimmedUrl = typeof entry.options.url === 'string' ? entry.options.url.trim() : '';
            if (trimmedUrl) {
                urlToId.set(trimmedUrl, entry.id);
            }
            upsertEntry(entry.id, entry.options);
            return;
        }
        const stored = server;
        const trimmedUrl = typeof stored.url === 'string' ? stored.url.trim() : '';
        if (trimmedUrl) {
            const existingId = urlToId.get(trimmedUrl);
            if (existingId) {
                upsertEntry(existingId, stored);
                return;
            }
            const baseId = `prop-${sanitizeIdSegment(trimmedUrl) || 'server'}`;
            let id = baseId;
            let suffix = 1;
            while (idInUse.has(id)) {
                id = `${baseId}-${suffix++}`;
            }
            urlToId.set(trimmedUrl, id);
            upsertEntry(id, stored);
            return;
        }
        let id;
        do {
            id = `prop-generated-${generatedCount++}-${index}`;
        } while (idInUse.has(id));
        upsertEntry(id, stored);
    });
    return entries;
};
const ModelContextPlaygroundInner = ({ className, additionalTools, additionalPrompts }) => {
    const { status: providerInitStatus, error: providerInitError, refreshProviders, isRefreshing, supportsRefresh } = useProviderRegistry();
    const modelContext = useModelContext();
    const mcpContext = useMcpServers();
    const theme = useTheme();
    const [isSettingsOpen, setIsSettingsOpen] = React.useState(false);
    const [activeView, setActiveView] = React.useState('chat');
    const mergedClassName = [theme.layout.appRoot, className].filter(Boolean).join(' ');
    const handleRetryProviders = React.useCallback(() => {
        if (isRefreshing || !supportsRefresh) {
            return;
        }
        void refreshProviders();
    }, [isRefreshing, refreshProviders, supportsRefresh]);
    const renderProviderInitializationState = () => {
        const message = providerInitStatus === 'loading'
            ? 'Initializing providers…'
            : 'Failed to initialize one or more providers.';
        const detailMessage = providerInitStatus === 'error'
            ? providerInitError instanceof Error
                ? providerInitError.message
                : typeof providerInitError === 'string'
                    ? providerInitError
                    : undefined
            : undefined;
        return (_jsx("div", { className: theme.layout.mainPanel, children: _jsx("div", { className: 'flex h-full items-center justify-center p-6 text-sm text-muted-foreground', children: _jsxs("div", { className: 'text-center', children: [_jsx("p", { className: 'font-medium text-foreground', children: message }), detailMessage && (_jsx("p", { className: 'mt-3 text-xs text-muted-foreground', children: detailMessage })), providerInitStatus === 'error' && supportsRefresh && (_jsx("button", { type: 'button', className: 'mt-4 inline-flex items-center justify-center rounded border border-border px-3 py-1.5 text-xs font-medium text-foreground hover:bg-muted disabled:cursor-not-allowed disabled:opacity-70', onClick: handleRetryProviders, disabled: isRefreshing, children: isRefreshing ? 'Retrying…' : 'Retry' }))] }) }) }));
    };
    return (_jsx("div", { className: mergedClassName, children: _jsx(AdditionalToolsProvider, { definitions: additionalTools, children: _jsx(CustomPromptsProvider, { propPrompts: additionalPrompts, children: _jsx("div", { className: 'flex flex-1 min-h-0 overflow-hidden', children: isSettingsOpen ? (_jsx("div", { id: 'playground-settings-panel', className: theme.layout.settingsPanel, children: _jsx(PlaygroundSettings, { onClose: () => setIsSettingsOpen(false) }) })) : (providerInitStatus === 'ready' ? (_jsx("div", { className: theme.layout.mainPanel, children: _jsx(ChatSessionsProvider, { children: _jsx(ChatProvider, { modelContext: modelContext, mcpContext: mcpContext, children: _jsx(SlashCommandPromptProvider, { children: _jsx(ChatDialog, { className: 'flex-1', onToggleSettings: () => setIsSettingsOpen((prev) => !prev), isSettingsOpen: isSettingsOpen, activeView: activeView, onSelectView: (view) => setActiveView(view) }) }) }) }) })) : (renderProviderInitializationState())) }) }) }) }));
};
const getPreferredColorScheme = () => {
    if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
        return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
    }
    return 'light';
};
export const ModelContextPlayground = ({ className, theme, themeOverrides, mcpServers, languageModels, additionalTools, additionalPrompts, getProviders, loadInitialCredentials, onCredentialsSubmit, onReady, attachmentCallbackHandler, systemPrompt, storageAdapter }) => {
    const initialServerEntries = React.useMemo(() => buildInitialServerEntries(mcpServers), [mcpServers]);
    const normalizedLanguageModelEntries = React.useMemo(() => coerceStoredModels(languageModels), [languageModels]);
    const [externalCredentialModels, setExternalCredentialModels] = React.useState([]);
    const [isLoadingCredentials, setIsLoadingCredentials] = React.useState(typeof loadInitialCredentials === 'function');
    const [credentialLoadError, setCredentialLoadError] = React.useState();
    const combinedInitialModels = React.useMemo(() => {
        if (externalCredentialModels.length === 0) {
            return normalizedLanguageModelEntries;
        }
        const merged = new Map();
        for (const model of normalizedLanguageModelEntries) {
            if (!model)
                continue;
            const key = typeof model.id === 'string' && model.id.length > 0
                ? model.id
                : `${model.provider}:${model.model}`;
            merged.set(key, model);
        }
        for (const model of externalCredentialModels) {
            if (!model)
                continue;
            const key = typeof model.id === 'string' && model.id.length > 0
                ? model.id
                : `${model.provider}:${model.model}`;
            merged.set(key, model);
        }
        return Array.from(merged.values());
    }, [normalizedLanguageModelEntries, externalCredentialModels]);
    const [systemPreference, setSystemPreference] = React.useState(() => getPreferredColorScheme());
    const [, bumpProviderRegistryVersion] = React.useState(0);
    const hasFactory = typeof getProviders === 'function';
    const hasCredentialLoader = typeof loadInitialCredentials === 'function';
    const supportsRefresh = hasFactory || hasCredentialLoader;
    const [resolvedProviders, setResolvedProviders] = React.useState([]);
    const [providerInitStatus, setProviderInitStatus] = React.useState(() => (supportsRefresh ? 'loading' : 'ready'));
    const [providerInitError, setProviderInitError] = React.useState();
    const [isRefreshingProviders, setIsRefreshingProviders] = React.useState(supportsRefresh);
    const onReadyFiredRef = React.useRef(false);
    const loadCredentials = React.useCallback(async () => {
        if (!loadInitialCredentials) {
            setCredentialLoadError(undefined);
            setIsLoadingCredentials(false);
            return;
        }
        setIsLoadingCredentials(true);
        try {
            const loadedModels = await loadInitialCredentials();
            const sanitized = coerceStoredModels(loadedModels);
            setExternalCredentialModels(sanitized);
            setCredentialLoadError(undefined);
        }
        catch (error) {
            setCredentialLoadError(error);
            throw error;
        }
        finally {
            setIsLoadingCredentials(false);
        }
    }, [loadInitialCredentials]);
    const providerPlugins = React.useMemo(() => {
        if (!resolvedProviders.length) {
            return [];
        }
        const unique = new Map();
        for (const plugin of resolvedProviders) {
            if (plugin && typeof plugin.id === 'string') {
                unique.set(plugin.id, plugin);
            }
        }
        return Array.from(unique.values());
    }, [resolvedProviders]);
    const refreshProviders = React.useCallback(async () => {
        if (!supportsRefresh) {
            setProviderInitError(undefined);
            setProviderInitStatus('ready');
            setIsRefreshingProviders(false);
            return;
        }
        setIsRefreshingProviders(true);
        setProviderInitStatus('loading');
        setProviderInitError(undefined);
        try {
            await loadCredentials();
        }
        catch (error) {
            setProviderInitError(error);
            setProviderInitStatus('error');
            setIsRefreshingProviders(false);
            throw error;
        }
        if (!getProviders) {
            setProviderInitStatus('ready');
            return;
        }
        try {
            const providerList = await getProviders();
            const sanitized = (Array.isArray(providerList) ? providerList : []).filter((plugin) => Boolean(plugin));
            setResolvedProviders(sanitized);
            if (sanitized.length === 0) {
                setProviderInitStatus('ready');
            }
        }
        catch (error) {
            setProviderInitError(error);
            setProviderInitStatus('error');
            setIsRefreshingProviders(false);
            throw error;
        }
    }, [supportsRefresh, loadCredentials, getProviders]);
    const isPlaygroundSettled = !isLoadingCredentials && (providerInitStatus === 'ready' || providerInitStatus === 'error');
    React.useEffect(() => {
        if (!isPlaygroundSettled || onReadyFiredRef.current) {
            return;
        }
        onReadyFiredRef.current = true;
        onReady?.();
    }, [isPlaygroundSettled, onReady]);
    React.useEffect(() => {
        if (!supportsRefresh) {
            return;
        }
        void refreshProviders().catch(() => {
            // errors handled within refreshProviders
        });
    }, [supportsRefresh, refreshProviders]);
    React.useEffect(() => {
        if (providerInitStatus !== 'loading') {
            setIsRefreshingProviders(false);
        }
    }, [providerInitStatus]);
    React.useEffect(() => {
        if (!supportsRefresh) {
            setIsRefreshingProviders(false);
            setProviderInitStatus('ready');
            setProviderInitError(undefined);
        }
    }, [supportsRefresh]);
    React.useEffect(() => {
        if (providerPlugins.length === 0) {
            if (!hasFactory) {
                setProviderInitError(undefined);
                setProviderInitStatus('ready');
            }
            return;
        }
        let cancelled = false;
        setProviderInitStatus('loading');
        setProviderInitError(undefined);
        const registerAll = async () => {
            let encounteredError;
            for (const plugin of providerPlugins) {
                try {
                    await registerProviderPlugin(plugin);
                }
                catch (error) {
                    if (!cancelled) {
                        console.error(`Failed to register provider plugin "${plugin.id}"`, error);
                    }
                    if (encounteredError === undefined) {
                        encounteredError = error;
                    }
                }
            }
            if (encounteredError) {
                throw encounteredError;
            }
        };
        void registerAll()
            .then(() => {
            if (!cancelled) {
                bumpProviderRegistryVersion((version) => version + 1);
                setProviderInitStatus('ready');
            }
        })
            .catch((error) => {
            if (!cancelled) {
                setProviderInitError(error);
                setProviderInitStatus('error');
            }
        });
        return () => {
            cancelled = true;
        };
    }, [providerPlugins, hasFactory]);
    React.useEffect(() => {
        if (theme !== systemTheme || typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
            return;
        }
        const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
        const updatePreference = (matches) => {
            setSystemPreference(matches ? 'dark' : 'light');
        };
        updatePreference(mediaQuery.matches);
        const listener = (event) => {
            updatePreference(event.matches);
        };
        if (typeof mediaQuery.addEventListener === 'function') {
            mediaQuery.addEventListener('change', listener);
            return () => {
                mediaQuery.removeEventListener('change', listener);
            };
        }
        mediaQuery.addListener(listener);
        return () => {
            mediaQuery.removeListener(listener);
        };
    }, [theme]);
    const themeProviderProps = React.useMemo(() => {
        if (theme && typeof theme === 'object') {
            return {
                theme,
                overrides: themeOverrides
            };
        }
        if (theme === systemTheme) {
            const baseTheme = systemPreference === 'dark' ? darkTheme : defaultTheme;
            const resolvedSystemTheme = themeOverrides ? createTheme(themeOverrides, baseTheme) : baseTheme;
            return {
                theme: resolvedSystemTheme,
                overrides: themeOverrides
            };
        }
        return {
            overrides: themeOverrides,
            initialThemeName: systemPreference
        };
    }, [theme, themeOverrides, systemPreference]);
    const handleCredentialSubmit = React.useCallback(async (payload) => {
        if (!onCredentialsSubmit) {
            return;
        }
        await onCredentialsSubmit(payload);
    }, [onCredentialsSubmit]);
    return (_jsx(CredentialSyncProvider, { onSubmit: handleCredentialSubmit, onRefresh: supportsRefresh ? refreshProviders : undefined, initialLoading: isLoadingCredentials, initialError: credentialLoadError, children: _jsx(ProviderRegistryProvider, { value: {
                status: providerInitStatus,
                error: providerInitError,
                refreshProviders,
                isRefreshing: isRefreshingProviders,
                hasFactory,
                supportsRefresh
            }, children: _jsx(StorageAdapterProvider, { adapter: storageAdapter, children: _jsx(ThemeProvider, { ...themeProviderProps, children: _jsx(ModelProvider, { initialModels: combinedInitialModels, children: _jsx(McpServersProvider, { initialServers: initialServerEntries, children: _jsx(ChatSettingsProvider, { attachmentCallback: attachmentCallbackHandler, systemPrompt: systemPrompt, children: _jsx(ModelContextPlaygroundInner, { className: className, additionalTools: additionalTools, additionalPrompts: additionalPrompts }) }) }) }) }) }) }) }));
};
export { ThemeProvider, createTheme, defaultTheme, darkTheme, systemTheme } from './theme';
export { registerProviderPlugin, ProviderPlugin } from './lib/providers';
export { CustomPromptsProvider, useCustomPrompts } from './contexts/customPrompts/useCustomPrompts';
export { useProviderRegistry } from './contexts/ProviderRegistryContext';
export { isToolPermissionConfigurable, getPermissionReason, resolveToolPermission, computeToolWithPermission, loadAdditionalToolPreferences, saveAdditionalToolPreferences, updateToolPermission, clearToolPermission, processAdditionalTools } from './lib/additionalToolPermissions';
export { ATTACHMENT_TOOLS_PREAMBLE } from './lib/attachmentTools';
