import { jsx as _jsx } from "react/jsx-runtime";
import React, { useEffect } from 'react';
import { useMcp } from 'react-mcp-hook';
import { useMcpServers } from '../contexts/McpContext';
import ServerSetupView from './ServerSetupView';
import ServerCheckingView from './ServerCheckingView';
import ServerErrorView from './ServerErrorView';
import ToolRunnerView from './ToolRunnerView';
import ServerDashboardView from './ServerDashboardView';
const areConnectionOptionsEqual = (a, b) => {
    if (a === b)
        return true;
    if (!a || !b)
        return false;
    if (a.url !== b.url)
        return false;
    if ((a.serverName ?? '') !== (b.serverName ?? ''))
        return false;
    const aHeaders = a.headers ?? {};
    const bHeaders = b.headers ?? {};
    const aKeys = Object.keys(aHeaders);
    const bKeys = Object.keys(bHeaders);
    if (aKeys.length !== bKeys.length)
        return false;
    for (const key of aKeys) {
        if (aHeaders[key] !== bHeaders[key]) {
            return false;
        }
    }
    return true;
};
export const McpServer = ({ uniqueId, onDelete, showStats = true, showTools = true, showPrompts = true }) => {
    const { getServer, updateServer, setServerEnabled, setToolPermission, getToolPermission: getServerToolPermission, setServerPrompts } = useMcpServers();
    const [oldConnectionOptions, setOldConnectionOptions] = React.useState(null);
    const [connectionOptions, setConnectionOptions] = React.useState(null);
    const [isHealthy, setIsHealthy] = React.useState(null);
    const [focusedTool, setFocusedTool] = React.useState(null);
    const promptFetchKeyRef = React.useRef(null);
    const hasFetchedPromptsRef = React.useRef(false);
    const [promptsLoading, setPromptsLoading] = React.useState(false);
    const [promptsError, setPromptsError] = React.useState(null);
    const serverRecord = getServer(uniqueId);
    const serverEnabled = serverRecord?.serverEnabled ?? true;
    const prompts = serverRecord?.cachedPrompts ?? [];
    const mcp = useMcp(connectionOptions);
    const { fetchTools, callTool, refetch, tools, error, abort, loading, serverInfo, protocolVersion, capabilities, lastEvent, listPrompts } = mcp;
    const autoFetchEnabled = serverRecord?.autoFetch ?? false;
    const supportsPromptExecution = typeof mcp.getPrompt === 'function';
    const fetchToolsRef = React.useRef(fetchTools);
    const abortRef = React.useRef(abort);
    useEffect(() => {
        fetchToolsRef.current = fetchTools;
    }, [fetchTools]);
    useEffect(() => {
        abortRef.current = abort;
    }, [abort]);
    const viewState = React.useMemo(() => {
        if (!connectionOptions) {
            return { kind: 'setup', oldOptions: oldConnectionOptions };
        }
        if (isHealthy === null) {
            return { kind: 'checking', options: connectionOptions };
        }
        if (isHealthy === false) {
            return { kind: 'error', options: connectionOptions, error };
        }
        if (focusedTool) {
            return { kind: 'tool', options: connectionOptions, tool: focusedTool };
        }
        return {
            kind: 'dashboard',
            options: connectionOptions,
            serverEnabled,
            tools,
            headers: connectionOptions.headers ?? {},
            autoFetchEnabled,
            loading,
            serverInfo,
            protocolVersion,
            capabilities,
            lastEvent,
            prompts,
            promptsLoading,
            promptsError,
            supportsPromptExecution
        };
    }, [
        autoFetchEnabled,
        connectionOptions,
        error,
        focusedTool,
        isHealthy,
        oldConnectionOptions,
        protocolVersion,
        serverEnabled,
        tools,
        serverInfo,
        capabilities,
        lastEvent,
        loading,
        prompts,
        promptsLoading,
        promptsError,
        supportsPromptExecution
    ]);
    const handleDelete = React.useCallback(() => {
        abort();
        onDelete?.(uniqueId);
    }, [abort, onDelete, uniqueId]);
    const handleServerToggle = React.useCallback((enabled) => {
        setServerEnabled(uniqueId, enabled);
    }, [setServerEnabled, uniqueId]);
    const handleConnectionSubmit = React.useCallback((opts) => {
        const normalizedOpts = {
            ...opts,
            headers: opts.headers ?? {}
        };
        setConnectionOptions(normalizedOpts);
        setOldConnectionOptions(normalizedOpts);
        const existing = getServer(uniqueId);
        updateServer(uniqueId, {
            ...(existing ?? {}),
            url: normalizedOpts.url,
            autoFetch: existing?.autoFetch ?? true,
            headers: normalizedOpts.headers,
            serverName: normalizedOpts.serverName,
            toolPreferences: existing?.toolPreferences ?? {},
            serverEnabled: existing?.serverEnabled ?? true,
            cachedPrompts: existing?.cachedPrompts,
            cachedPromptsUpdatedAt: existing?.cachedPromptsUpdatedAt
        });
    }, [getServer, uniqueId, updateServer]);
    const handleConnectionCancel = React.useCallback((previous) => {
        setConnectionOptions(previous);
    }, []);
    const handleEditConnection = React.useCallback(() => {
        setConnectionOptions(null);
    }, []);
    const handleToolPermissionChange = React.useCallback((toolName, permission) => {
        setToolPermission(uniqueId, toolName, permission);
    }, [setToolPermission, uniqueId]);
    const handleFocusTool = React.useCallback((tool) => {
        setFocusedTool(tool);
    }, []);
    const fetchAllPrompts = React.useCallback(async () => {
        const load = async (cursor, collected = []) => {
            const result = await listPrompts(cursor ? { cursor } : undefined);
            if (result.error) {
                throw result.error;
            }
            const combined = [...collected, ...result.prompts];
            if (result.nextCursor) {
                return await load(result.nextCursor, combined);
            }
            return combined;
        };
        return await load(undefined, []);
    }, [listPrompts]);
    useEffect(() => {
        const saved = getServer(uniqueId);
        if (!saved) {
            return;
        }
        const normalized = {
            serverName: saved.serverName ?? saved.url ?? 'New MCP Server',
            url: saved.url ?? '',
            headers: typeof saved.headers === 'object' && saved.headers !== null && !Array.isArray(saved.headers)
                ? saved.headers
                : {}
        };
        setOldConnectionOptions((prev) => (areConnectionOptionsEqual(prev, normalized) ? prev : normalized));
        if (normalized.url) {
            setConnectionOptions((prev) => (areConnectionOptionsEqual(prev, normalized) ? prev : normalized));
        }
        else {
            setConnectionOptions((prev) => (prev === null ? prev : null));
        }
    }, [getServer, uniqueId]);
    useEffect(() => {
        const key = connectionOptions?.url ?? null;
        if (promptFetchKeyRef.current !== key) {
            promptFetchKeyRef.current = key;
            hasFetchedPromptsRef.current = false;
        }
    }, [connectionOptions?.url]);
    useEffect(() => {
        if (!connectionOptions) {
            setIsHealthy(null);
            return;
        }
        setIsHealthy(null);
        let cancelled = false;
        fetchToolsRef.current()
            .then(() => {
            if (!cancelled)
                setIsHealthy(true);
        })
            .catch(() => {
            if (!cancelled)
                setIsHealthy(false);
        });
        return () => {
            cancelled = true;
            abortRef.current?.();
        };
    }, [connectionOptions]);
    useEffect(() => {
        if (!connectionOptions || isHealthy !== true || !serverEnabled) {
            return;
        }
        const hasCachedPrompts = (serverRecord?.cachedPrompts?.length ?? 0) > 0;
        if (hasFetchedPromptsRef.current) {
            return;
        }
        hasFetchedPromptsRef.current = true;
        let cancelled = false;
        setPromptsLoading(!hasCachedPrompts);
        setPromptsError(null);
        fetchAllPrompts()
            .then((loadedPrompts) => {
            if (cancelled)
                return;
            setServerPrompts(uniqueId, loadedPrompts.length > 0 ? loadedPrompts : undefined);
        })
            .catch((err) => {
            if (cancelled)
                return;
            setPromptsError(err instanceof Error ? err.message : 'Failed to load prompts.');
        })
            .finally(() => {
            if (cancelled)
                return;
            setPromptsLoading(false);
        });
        return () => {
            cancelled = true;
        };
    }, [connectionOptions, fetchAllPrompts, isHealthy, serverEnabled, serverRecord?.cachedPrompts?.length, serverRecord?.cachedPromptsUpdatedAt, setServerPrompts, uniqueId]);
    const handlePromptsRefresh = React.useCallback(async () => {
        if (!connectionOptions || isHealthy !== true || !serverEnabled) {
            return;
        }
        hasFetchedPromptsRef.current = true;
        setPromptsLoading(true);
        setPromptsError(null);
        try {
            const loadedPrompts = await fetchAllPrompts();
            setServerPrompts(uniqueId, loadedPrompts.length > 0 ? loadedPrompts : undefined);
        }
        catch (err) {
            setPromptsError(err instanceof Error ? err.message : 'Failed to load prompts.');
        }
        finally {
            setPromptsLoading(false);
        }
    }, [connectionOptions, fetchAllPrompts, isHealthy, serverEnabled, setServerPrompts, uniqueId]);
    useEffect(() => {
        if (!serverEnabled) {
            hasFetchedPromptsRef.current = false;
            setPromptsLoading(false);
            setPromptsError(null);
            setServerPrompts(uniqueId, undefined);
            return;
        }
        hasFetchedPromptsRef.current = false;
    }, [serverEnabled, setServerPrompts, uniqueId]);
    const handleRefreshAll = React.useCallback(() => {
        void refetch();
        void handlePromptsRefresh();
    }, [handlePromptsRefresh, refetch]);
    const handleRunPrompt = React.useCallback(async (promptName, args) => {
        const getPrompt = mcp.getPrompt;
        if (typeof getPrompt !== 'function') {
            return {
                prompt: undefined,
                error: new Error('Prompt execution is not supported by this MCP client.')
            };
        }
        try {
            const result = await getPrompt(promptName, args);
            if (result.error) {
                return {
                    prompt: result.prompt,
                    error: result.error
                };
            }
            return {
                prompt: result.prompt
            };
        }
        catch (error) {
            return {
                prompt: undefined,
                error: error instanceof Error ? error : new Error('Failed to fetch prompt output.')
            };
        }
    }, [mcp]);
    useEffect(() => {
        if (!serverRecord || tools.length === 0) {
            return;
        }
        const existingPreferences = serverRecord.toolPreferences ?? {};
        const normalizedPreferences = {};
        for (const tool of tools) {
            const currentValue = existingPreferences[tool.name] ?? 'enabled';
            normalizedPreferences[tool.name] = currentValue;
        }
        let changed = false;
        const existingKeys = Object.keys(existingPreferences);
        const normalizedKeys = Object.keys(normalizedPreferences);
        if (existingKeys.length !== normalizedKeys.length) {
            changed = true;
        }
        else {
            for (const key of normalizedKeys) {
                if (existingPreferences[key] !== normalizedPreferences[key]) {
                    changed = true;
                    break;
                }
            }
        }
        if (changed) {
            updateServer(uniqueId, {
                ...serverRecord,
                toolPreferences: normalizedPreferences
            });
        }
    }, [serverRecord, tools, updateServer, uniqueId]);
    switch (viewState.kind) {
        case 'setup':
            return (_jsx(ServerSetupView, { oldOptions: viewState.oldOptions, onSubmit: handleConnectionSubmit, onCancel: handleConnectionCancel, onDelete: handleDelete }));
        case 'checking':
            return _jsx(ServerCheckingView, { options: viewState.options, onDelete: handleDelete });
        case 'error':
            return (_jsx(ServerErrorView, { options: viewState.options, error: viewState.error, onRetry: refetch, onEdit: handleEditConnection, onDelete: handleDelete }));
        case 'tool':
            return (_jsx(ToolRunnerView, { tool: viewState.tool, serverName: viewState.options.serverName, onBack: () => handleFocusTool(null), callTool: callTool }));
        case 'dashboard':
            return (_jsx(ServerDashboardView, { options: viewState.options, tools: viewState.tools, serverEnabled: viewState.serverEnabled, onToggleServer: handleServerToggle, onEdit: handleEditConnection, onRefresh: handleRefreshAll, onDelete: handleDelete, onViewTool: handleFocusTool, getToolPermission: (toolName) => getServerToolPermission(uniqueId, toolName), onChangeToolPermission: handleToolPermissionChange, headers: viewState.headers, autoFetchEnabled: viewState.autoFetchEnabled, showStats: showStats, showTools: showTools, showPrompts: showPrompts, serverInfo: viewState.serverInfo, protocolVersion: viewState.protocolVersion, capabilities: viewState.capabilities, lastEvent: viewState.lastEvent, isLoadingTools: viewState.loading, prompts: viewState.prompts, promptsError: viewState.promptsError, isLoadingPrompts: viewState.promptsLoading, onRefreshPrompts: handlePromptsRefresh, onRunPrompt: viewState.supportsPromptExecution ? handleRunPrompt : undefined, supportsPromptExecution: viewState.supportsPromptExecution }));
        default:
            return null;
    }
};
export default McpServer;
