'use client';
import React from 'react';
import { useLocalStorageState } from '../hooks/useLocalStorage';
const EMPTY_STATE = {
    order: [],
    byId: {},
    selectedId: null
};
const McpServersContext = React.createContext(undefined);
const generateServerId = () => {
    if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
        return crypto.randomUUID();
    }
    return `mcp-${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
};
const normalizeToolPermission = (value) => {
    if (typeof value === 'string') {
        const normalized = value.trim().toLowerCase();
        if (normalized === 'enabled') {
            return 'enabled';
        }
        if (normalized === 'disabled') {
            return 'disabled';
        }
        if (normalized === 'ask_first' || normalized === 'ask-first' || normalized === 'ask') {
            return 'ask_first';
        }
    }
    if (typeof value === 'boolean') {
        return value ? 'enabled' : 'disabled';
    }
    return undefined;
};
const normalizeToolPreferences = (preferences) => {
    if (!preferences) {
        return undefined;
    }
    const normalized = {};
    for (const [toolName, enabled] of Object.entries(preferences)) {
        const permission = normalizeToolPermission(enabled);
        if (permission) {
            normalized[toolName] = permission;
        }
    }
    return Object.keys(normalized).length > 0 ? normalized : undefined;
};
const normalizeServerOptions = (options) => {
    const { toolPreferences, serverEnabled, cachedPrompts, cachedPromptsUpdatedAt, ...rest } = options;
    const { method: _legacyMethod, ...restWithoutMethod } = rest;
    void _legacyMethod;
    const normalizedUrl = typeof restWithoutMethod.url === 'string'
        ? restWithoutMethod.url.trim()
        : restWithoutMethod.url;
    const normalizedOptions = {
        ...restWithoutMethod,
        url: normalizedUrl,
        serverEnabled: serverEnabled ?? true,
        toolPreferences: normalizeToolPreferences(toolPreferences),
        cachedPrompts: cachedPrompts?.length ? cachedPrompts : undefined,
        cachedPromptsUpdatedAt: cachedPromptsUpdatedAt ?? undefined
    };
    return normalizedOptions;
};
const trimmedUrl = (url) => {
    if (typeof url !== 'string')
        return undefined;
    const value = url.trim();
    return value.length > 0 ? value : undefined;
};
const findServerIdByUrl = (collection, url) => {
    const target = trimmedUrl(url);
    if (!target)
        return undefined;
    for (const [id, server] of Object.entries(collection)) {
        if (trimmedUrl(server.url) === target) {
            return id;
        }
    }
    return undefined;
};
const storedServersEqual = (a, b) => {
    return JSON.stringify(a) === JSON.stringify(b);
};
export const McpServersProvider = ({ children, initialServers, storageKey = 'mcp-server-options' }) => {
    const { value: state, update: updateState, setValue } = useLocalStorageState(storageKey, EMPTY_STATE);
    React.useEffect(() => {
        if (!initialServers?.length)
            return;
        updateState((prev) => {
            let nextById = prev.byId;
            let nextOrder = prev.order;
            let changed = false;
            for (const entry of initialServers) {
                const normalized = normalizeServerOptions(entry.options);
                const candidateUrl = trimmedUrl(normalized.url);
                const existingId = findServerIdByUrl(nextById, candidateUrl);
                const targetId = existingId ?? entry.id ?? generateServerId();
                const existingOptions = nextById[targetId];
                if (existingOptions) {
                    const merged = {
                        ...existingOptions,
                        ...normalized,
                        toolPreferences: normalized.toolPreferences ?? existingOptions.toolPreferences
                    };
                    if (!storedServersEqual(existingOptions, merged)) {
                        nextById = {
                            ...nextById,
                            [targetId]: merged
                        };
                        changed = true;
                    }
                }
                else {
                    nextById = {
                        ...nextById,
                        [targetId]: normalized
                    };
                    if (!nextOrder.includes(targetId)) {
                        nextOrder = [...nextOrder, targetId];
                    }
                    changed = true;
                }
            }
            if (!changed) {
                return prev;
            }
            let nextSelectedId = prev.selectedId;
            if (nextSelectedId && !nextById[nextSelectedId]) {
                nextSelectedId = nextOrder.length > 0 ? nextOrder[nextOrder.length - 1] : null;
            }
            return {
                order: nextOrder,
                byId: nextById,
                selectedId: nextSelectedId
            };
        });
    }, [initialServers, updateState]);
    const addServer = React.useCallback((options, providedId) => {
        let resolvedId = providedId ?? generateServerId();
        const normalizedOptions = normalizeServerOptions({
            ...options,
            toolPreferences: options.toolPreferences
        });
        const candidateUrl = trimmedUrl(normalizedOptions.url);
        updateState((prev) => {
            const duplicateEntry = candidateUrl
                ? Object.entries(prev.byId).find(([, server]) => trimmedUrl(server.url) === candidateUrl)
                : undefined;
            if (duplicateEntry) {
                const [existingId, existingOptions] = duplicateEntry;
                resolvedId = existingId;
                const mergedOptions = {
                    ...existingOptions,
                    ...normalizedOptions
                };
                return {
                    order: prev.order,
                    byId: {
                        ...prev.byId,
                        [existingId]: mergedOptions
                    },
                    selectedId: prev.selectedId ?? existingId
                };
            }
            const alreadyExists = prev.byId[resolvedId] !== undefined;
            const order = alreadyExists ? prev.order : [...prev.order, resolvedId];
            return {
                order,
                byId: {
                    ...prev.byId,
                    [resolvedId]: normalizedOptions
                },
                selectedId: prev.selectedId ?? resolvedId
            };
        });
        return resolvedId;
    }, [updateState]);
    const updateServer = React.useCallback((id, options) => {
        updateState((prev) => {
            if (!prev.byId[id]) {
                return prev;
            }
            const existing = prev.byId[id];
            const merged = {
                ...existing,
                ...options,
                toolPreferences: options.toolPreferences ?? existing.toolPreferences
            };
            const normalized = normalizeServerOptions(merged);
            const candidateUrl = trimmedUrl(normalized.url);
            if (candidateUrl) {
                const duplicateEntry = Object.entries(prev.byId).find(([otherId, server]) => (otherId !== id && trimmedUrl(server.url) === candidateUrl));
                if (duplicateEntry) {
                    const [duplicateId, duplicateOptions] = duplicateEntry;
                    const mergedDuplicate = {
                        ...duplicateOptions,
                        ...normalized
                    };
                    const nextById = {
                        ...prev.byId,
                        [duplicateId]: mergedDuplicate
                    };
                    delete nextById[id];
                    const nextOrder = prev.order.filter((entryId) => entryId !== id);
                    const nextSelectedId = prev.selectedId === id ? duplicateId : prev.selectedId;
                    return {
                        order: nextOrder,
                        byId: nextById,
                        selectedId: nextSelectedId
                    };
                }
            }
            return {
                ...prev,
                byId: {
                    ...prev.byId,
                    [id]: normalized
                }
            };
        });
    }, [updateState]);
    const removeServer = React.useCallback((id) => {
        updateState((prev) => {
            if (!prev.byId[id]) {
                return prev;
            }
            const nextById = { ...prev.byId };
            delete nextById[id];
            const nextOrder = prev.order.filter((entryId) => entryId !== id);
            const nextSelectedId = prev.selectedId === id ? (nextOrder.length > 0 ? nextOrder[nextOrder.length - 1] : null) : prev.selectedId;
            return {
                order: nextOrder,
                byId: nextById,
                selectedId: nextSelectedId
            };
        });
    }, [updateState]);
    const selectServer = React.useCallback((id) => {
        updateState((prev) => {
            if (id === null) {
                if (prev.selectedId === null)
                    return prev;
                return {
                    ...prev,
                    selectedId: null
                };
            }
            if (!prev.byId[id]) {
                return prev;
            }
            if (prev.selectedId === id) {
                return prev;
            }
            return {
                ...prev,
                selectedId: id
            };
        });
    }, [updateState]);
    const clearServers = React.useCallback(() => {
        setValue({
            order: [],
            byId: {},
            selectedId: null
        });
    }, [setValue]);
    const getServer = React.useCallback((id) => {
        const server = state.byId[id];
        return server ? normalizeServerOptions(server) : undefined;
    }, [state.byId]);
    const setServerEnabled = React.useCallback((id, enabled) => {
        updateState((prev) => {
            const server = prev.byId[id];
            if (!server) {
                return prev;
            }
            if ((server.serverEnabled ?? true) === enabled) {
                return prev;
            }
            return {
                ...prev,
                byId: {
                    ...prev.byId,
                    [id]: {
                        ...server,
                        serverEnabled: enabled
                    }
                }
            };
        });
    }, [updateState]);
    const setToolPermission = React.useCallback((id, toolName, permission) => {
        updateState((prev) => {
            const server = prev.byId[id];
            if (!server) {
                return prev;
            }
            const normalizedPermission = normalizeToolPermission(permission) ?? 'enabled';
            const currentPreferences = server.toolPreferences ?? {};
            const currentPermission = normalizeToolPermission(currentPreferences[toolName]) ?? 'enabled';
            if (currentPermission === normalizedPermission) {
                return prev;
            }
            const nextPreferences = {
                ...currentPreferences,
                [toolName]: normalizedPermission
            };
            return {
                ...prev,
                byId: {
                    ...prev.byId,
                    [id]: {
                        ...server,
                        toolPreferences: nextPreferences,
                        serverEnabled: server.serverEnabled ?? true
                    }
                }
            };
        });
    }, [updateState]);
    const getToolPermission = React.useCallback((id, toolName) => {
        const server = state.byId[id];
        if (!server) {
            return 'enabled';
        }
        const preferences = server.toolPreferences ?? {};
        return normalizeToolPermission(preferences[toolName]) ?? 'enabled';
    }, [state.byId]);
    const setServerPrompts = React.useCallback((id, prompts) => {
        updateState((prev) => {
            const server = prev.byId[id];
            if (!server) {
                return prev;
            }
            const normalizedPrompts = prompts && prompts.length > 0 ? [...prompts] : undefined;
            const existingPrompts = server.cachedPrompts ?? undefined;
            const existingTimestamp = server.cachedPromptsUpdatedAt ?? undefined;
            const promptsChanged = JSON.stringify(existingPrompts ?? []) !== JSON.stringify(normalizedPrompts ?? []);
            const timestamp = normalizedPrompts ? Date.now() : undefined;
            if (!promptsChanged && existingTimestamp === timestamp) {
                return prev;
            }
            return {
                ...prev,
                byId: {
                    ...prev.byId,
                    [id]: {
                        ...server,
                        cachedPrompts: normalizedPrompts,
                        cachedPromptsUpdatedAt: timestamp
                    }
                }
            };
        });
    }, [updateState]);
    const isToolEnabled = React.useCallback((id, toolName) => {
        return getToolPermission(id, toolName) === 'enabled';
    }, [getToolPermission]);
    const servers = React.useMemo(() => state.order
        .map((id) => ({ id, options: state.byId[id] }))
        .filter((entry) => entry.options !== undefined)
        .map((entry) => ({
        id: entry.id,
        options: normalizeServerOptions(entry.options)
    })), [state.byId, state.order]);
    const contextValue = React.useMemo(() => ({
        state,
        servers,
        addServer,
        updateServer,
        removeServer,
        selectServer,
        clearServers,
        getServer,
        setServerEnabled,
        setToolPermission,
        getToolPermission,
        isToolEnabled,
        setServerPrompts
    }), [state, servers, addServer, updateServer, removeServer, selectServer, clearServers, getServer, setServerEnabled, setToolPermission, getToolPermission, isToolEnabled, setServerPrompts]);
    return React.createElement(McpServersContext.Provider, { value: contextValue }, children);
};
export const useMcpServers = () => {
    const context = React.useContext(McpServersContext);
    if (!context) {
        throw new Error('useMcpServers must be used within an McpServersProvider');
    }
    return context;
};
export default McpServersContext;
