import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { memo, useState, useCallback, useMemo, useEffect, useRef } from 'react';
import { ChevronDown, ChevronRight, ClipboardCopy, ExternalLink, FolderDot, Globe, Laptop, Loader2, Lock, Plug, Plus, Trash2, Wrench, } from 'lucide-react';
import { Button } from '../ui/Button';
import { Modal } from '../ui/Modal';
import { useMCPStore } from '../../stores/mcpStore';
import { useQueryClient } from '@tanstack/react-query';
import { useMCPServers, useStartMCPServer, useStopMCPServer, useRemoveMCPServer, useAuthenticateMCPServer, useMCPAuthStatus, useCopilotDevicePoller, } from '../../hooks/useMCP';
import { openUrl } from '../../lib/open-url';
import { AddMCPServerModal } from './AddMCPServerModal';
const ToggleSwitch = memo(function ToggleSwitch({ checked, loading, onChange, disabled, }) {
    return (_jsx("button", { type: "button", role: "switch", "aria-checked": checked, disabled: disabled || loading, onClick: (e) => {
            e.stopPropagation();
            onChange();
        }, className: `relative inline-flex h-5 w-9 flex-shrink-0 items-center rounded-full transition-colors duration-200 focus-visible:outline-none disabled:opacity-50 disabled:cursor-not-allowed ${checked ? 'bg-green-500' : 'bg-muted-foreground/30'}`, children: _jsx("span", { className: `inline-block h-3.5 w-3.5 rounded-full transition-transform duration-200 ${checked ? 'translate-x-[18px]' : 'translate-x-[3px]'} ${loading ? 'bg-transparent' : 'bg-white'}`, children: loading && _jsx(Loader2, { className: "w-3.5 h-3.5 animate-spin text-white" }) }) }));
});
const CopilotDeviceAuth = memo(function CopilotDeviceAuth({ userCode, verificationUri, }) {
    const [copied, setCopied] = useState(false);
    const handleCopy = useCallback(() => {
        navigator.clipboard.writeText(userCode).then(() => {
            setCopied(true);
            setTimeout(() => setCopied(false), 2000);
        });
    }, [userCode]);
    return (_jsx("div", { className: "px-3 pb-2.5 pt-0", children: _jsxs("div", { className: "rounded-md bg-yellow-500/10 border border-yellow-500/20 p-2 space-y-1.5", children: [_jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [_jsx(Loader2, { className: "w-3 h-3 animate-spin text-yellow-500 flex-shrink-0" }), _jsx("span", { className: "text-yellow-500/80", children: "Enter code at GitHub:" })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("code", { className: "text-sm font-mono font-bold text-yellow-400 tracking-wider", children: userCode }), _jsx("button", { type: "button", onClick: handleCopy, className: "text-yellow-500/60 hover:text-yellow-400 transition-colors", title: "Copy code", children: _jsx(ClipboardCopy, { className: "w-3.5 h-3.5" }) }), copied && _jsx("span", { className: "text-xs text-green-400", children: "Copied!" })] }), _jsxs("a", { href: verificationUri, target: "_blank", rel: "noopener noreferrer", onClick: (e) => {
                        e.preventDefault();
                        openUrl(verificationUri);
                    }, className: "inline-flex items-center gap-1 text-xs text-yellow-400 hover:text-yellow-300 underline underline-offset-2", children: ["Open GitHub login", _jsx(ExternalLink, { className: "w-3 h-3" })] })] }) }));
});
const MCPServerCard = memo(function MCPServerCard({ server, isLoading, authUrl, copilotDevice, onStart, onStop, onRemove, onAuth, }) {
    const [showTools, setShowTools] = useState(false);
    const hasTools = server.connected && server.tools.length > 0;
    const isRemote = server.transport === 'http' || server.transport === 'sse';
    const isAwaitingAuth = (!!authUrl || !!copilotDevice) && !server.connected;
    const handleToggle = useCallback(() => {
        if (server.authRequired && !server.connected) {
            onAuth();
        }
        else if (server.connected) {
            onStop();
        }
        else {
            onStart();
        }
    }, [server.connected, server.authRequired, onAuth, onStop, onStart]);
    const toggleTools = useCallback(() => {
        if (hasTools)
            setShowTools((prev) => !prev);
    }, [hasTools]);
    return (_jsxs("div", { className: `rounded-lg border transition-colors duration-200 group ${server.connected
            ? 'border-green-500/30 bg-green-500/5'
            : isAwaitingAuth
                ? 'border-yellow-500/30 bg-yellow-500/5'
                : 'border-border bg-transparent'}`, children: [_jsxs("div", { className: "flex items-center gap-3 px-3 py-2.5", children: [_jsx(ToggleSwitch, { checked: server.connected, loading: isLoading || isAwaitingAuth, onChange: handleToggle }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-sm font-medium truncate", children: server.name }), isRemote && (_jsx(Globe, { className: "w-3 h-3 text-muted-foreground flex-shrink-0" })), server.authRequired && !server.connected && (_jsx(Lock, { className: "w-3 h-3 text-yellow-500 flex-shrink-0" }))] }), _jsxs("div", { className: "flex items-center gap-1.5 mt-0.5", children: [_jsx("span", { className: "text-xs text-muted-foreground truncate", children: isRemote
                                            ? server.url
                                            : `${server.command ?? ''} ${server.args.join(' ')}` }), _jsx("span", { className: "flex items-center flex-shrink-0 opacity-50", title: server.scope === 'project' ? 'Project-local' : 'Global', children: server.scope === 'project' ? (_jsx(FolderDot, { className: "w-3 h-3" })) : (_jsx(Laptop, { className: "w-3 h-3" })) })] })] }), _jsxs("div", { className: "flex items-center gap-0.5 flex-shrink-0", children: [hasTools && (_jsxs("button", { type: "button", onClick: toggleTools, className: "flex items-center gap-0.5 text-xs text-muted-foreground hover:text-foreground px-1.5 py-1 rounded transition-colors", children: [_jsx(Wrench, { className: "w-3 h-3" }), server.tools.length, showTools ? (_jsx(ChevronDown, { className: "w-3 h-3" })) : (_jsx(ChevronRight, { className: "w-3 h-3" }))] })), _jsx(Button, { variant: "ghost", size: "icon", onClick: onRemove, title: "Remove server", className: "h-6 w-6 opacity-0 group-hover:opacity-100 transition-opacity", children: _jsx(Trash2, { className: "w-3 h-3 text-muted-foreground hover:text-red-400" }) })] })] }), copilotDevice && !server.connected && (_jsx(CopilotDeviceAuth, { userCode: copilotDevice.userCode, verificationUri: copilotDevice.verificationUri })), !copilotDevice && isAwaitingAuth && authUrl && (_jsx("div", { className: "px-3 pb-2.5 pt-0", children: _jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [_jsx(Loader2, { className: "w-3 h-3 animate-spin text-yellow-500 flex-shrink-0" }), _jsx("span", { className: "text-yellow-500/80", children: "Waiting for auth..." }), _jsxs("a", { href: authUrl, target: "_blank", rel: "noopener noreferrer", onClick: (e) => {
                                e.preventDefault();
                                openUrl(authUrl);
                            }, className: "inline-flex items-center gap-0.5 text-yellow-400 hover:text-yellow-300 underline underline-offset-2", children: ["Open login", _jsx(ExternalLink, { className: "w-3 h-3" })] })] }) })), hasTools && showTools && (_jsx("div", { className: "px-3 pb-2.5 pt-0", children: _jsx("div", { className: "flex flex-wrap gap-1", children: server.tools.map((tool) => (_jsx("span", { className: "text-xs bg-muted px-1.5 py-0.5 rounded", title: tool, children: tool.split('__').pop() }, tool))) }) }))] }));
});
function useAuthPoller(name, onAuthenticated) {
    const { data } = useMCPAuthStatus(name);
    const prevAuth = useRef(false);
    useEffect(() => {
        if (data?.authenticated && !prevAuth.current) {
            onAuthenticated();
        }
        prevAuth.current = data?.authenticated ?? false;
    }, [data?.authenticated, onAuthenticated]);
}
export const MCPSidebar = memo(function MCPSidebar() {
    const isExpanded = useMCPStore((s) => s.isExpanded);
    const collapseSidebar = useMCPStore((s) => s.collapseSidebar);
    const servers = useMCPStore((s) => s.servers);
    const loading = useMCPStore((s) => s.loading);
    const authUrls = useMCPStore((s) => s.authUrls);
    const setAuthUrl = useMCPStore((s) => s.setAuthUrl);
    const setLoading = useMCPStore((s) => s.setLoading);
    const setCopilotDevice = useMCPStore((s) => s.setCopilotDevice);
    const { isLoading: isFetching } = useMCPServers();
    const startServer = useStartMCPServer();
    const stopServer = useStopMCPServer();
    const removeServer = useRemoveMCPServer();
    const authServer = useAuthenticateMCPServer();
    const copilotDevice = useCopilotDevicePoller();
    const [isAddModalOpen, setIsAddModalOpen] = useState(false);
    const [pollingServer, setPollingServer] = useState(null);
    const [deleteTarget, setDeleteTarget] = useState(null);
    const queryClient = useQueryClient();
    const handleAuthCompleted = useCallback(() => {
        if (pollingServer) {
            setAuthUrl(pollingServer, null);
            setPollingServer(null);
            queryClient.invalidateQueries({ queryKey: ['mcp', 'servers'] });
        }
    }, [pollingServer, setAuthUrl, queryClient]);
    useAuthPoller(pollingServer, handleAuthCompleted);
    useEffect(() => {
        for (const name of loading) {
            const server = servers.find((s) => s.name === name);
            if (server?.connected) {
                setLoading(name, false);
            }
        }
    }, [servers, loading, setLoading]);
    const handleCopilotDeviceResponse = useCallback((name, result) => {
        if (result.sessionId && result.userCode && result.verificationUri) {
            setCopilotDevice({
                sessionId: result.sessionId,
                userCode: result.userCode,
                verificationUri: result.verificationUri,
                interval: result.interval ?? 5,
                serverName: name,
            });
            openUrl(result.verificationUri);
        }
    }, [setCopilotDevice]);
    const handleAuth = useCallback(async (name) => {
        try {
            setLoading(name, true);
            const result = await authServer.mutateAsync(name);
            if (result.authType === 'copilot-device') {
                if (result.authenticated) {
                    setLoading(name, false);
                    queryClient.invalidateQueries({ queryKey: ['mcp', 'servers'] });
                    return;
                }
                handleCopilotDeviceResponse(name, result);
            }
            else if (result.authUrl) {
                setAuthUrl(name, result.authUrl);
                setPollingServer(name);
                openUrl(result.authUrl);
            }
            else {
                setLoading(name, false);
            }
        }
        catch {
            setLoading(name, false);
            setAuthUrl(name, null);
        }
    }, [
        authServer,
        setAuthUrl,
        setLoading,
        handleCopilotDeviceResponse,
        queryClient,
    ]);
    const handleStart = useCallback(async (name) => {
        try {
            setLoading(name, true);
            const result = await startServer.mutateAsync(name);
            if (result.authType === 'copilot-device' && !result.connected) {
                handleCopilotDeviceResponse(name, result);
            }
            else if (result.authRequired && result.authUrl) {
                setAuthUrl(name, result.authUrl);
                setPollingServer(name);
                openUrl(result.authUrl);
            }
            else {
                setLoading(name, false);
            }
        }
        catch {
            setLoading(name, false);
            setAuthUrl(name, null);
        }
    }, [startServer, setAuthUrl, setLoading, handleCopilotDeviceResponse]);
    const sortedServers = useMemo(() => {
        return [...servers].sort((a, b) => {
            if (a.connected && !b.connected)
                return -1;
            if (!a.connected && b.connected)
                return 1;
            return a.name.localeCompare(b.name);
        });
    }, [servers]);
    if (!isExpanded)
        return null;
    const connectedCount = servers.filter((s) => s.connected).length;
    return (_jsxs("div", { className: "w-80 border-l border-border bg-background flex flex-col h-full", children: [_jsxs("div", { className: "h-14 flex items-center justify-between px-3 border-b border-border", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Plug, { className: "w-4 h-4 text-muted-foreground" }), _jsx("span", { className: "font-medium text-sm", children: "MCP Servers" }), connectedCount > 0 && (_jsxs("span", { className: "text-xs bg-green-500/20 text-green-400 px-1.5 py-0.5 rounded-full", children: [connectedCount, " active"] }))] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Button, { variant: "ghost", size: "icon", onClick: () => setIsAddModalOpen(true), title: "Add MCP server", className: "h-7 w-7", children: _jsx(Plus, { className: "w-4 h-4" }) }), _jsx(Button, { variant: "ghost", size: "icon", onClick: collapseSidebar, title: "Close sidebar", children: _jsx(ChevronRight, { className: "w-4 h-4" }) })] })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: isFetching && servers.length === 0 ? (_jsxs("div", { className: "flex items-center justify-center h-32 text-muted-foreground", children: [_jsx(Loader2, { className: "w-4 h-4 animate-spin mr-2" }), "Loading..."] })) : servers.length === 0 ? (_jsxs("div", { className: "p-4 text-sm text-muted-foreground space-y-3", children: [_jsx("p", { children: "No MCP servers configured." }), _jsxs(Button, { variant: "primary", size: "sm", onClick: () => setIsAddModalOpen(true), className: "w-full", children: [_jsx(Plus, { className: "w-3 h-3 mr-1" }), "Add MCP Server"] }), _jsxs("p", { className: "text-xs", children: ["Or add servers to", ' ', _jsx("code", { className: "bg-muted px-1 py-0.5 rounded text-xs", children: ".otto/config.json" })] })] })) : (_jsx("div", { className: "p-2 space-y-1.5", children: sortedServers.map((server) => (_jsx(MCPServerCard, { server: server, isLoading: loading.has(server.name), authUrl: authUrls.get(server.name), copilotDevice: copilotDevice?.serverName === server.name
                            ? copilotDevice
                            : null, onStart: () => handleStart(server.name), onStop: () => stopServer.mutate(server.name), onRemove: () => setDeleteTarget(server.name), onAuth: () => handleAuth(server.name) }, server.name))) })) }), _jsx(AddMCPServerModal, { isOpen: isAddModalOpen, onClose: () => setIsAddModalOpen(false) }), _jsxs(Modal, { isOpen: !!deleteTarget, onClose: () => setDeleteTarget(null), title: "Remove MCP Server", maxWidth: "sm", showCloseButton: false, children: [_jsxs("p", { className: "text-sm text-muted-foreground mb-4", children: ["Are you sure you want to remove", ' ', _jsx("span", { className: "font-medium text-foreground", children: deleteTarget }), "? This will stop the server and remove its configuration."] }), _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { variant: "secondary", size: "sm", onClick: () => setDeleteTarget(null), children: "Cancel" }), _jsx(Button, { variant: "primary", size: "sm", className: "bg-red-500 hover:bg-red-600 text-white", onClick: () => {
                                    if (deleteTarget) {
                                        removeServer.mutate(deleteTarget);
                                    }
                                    setDeleteTarget(null);
                                }, children: "Remove" })] })] })] }));
});
//# sourceMappingURL=MCPSidebar.js.map