import React, { useEffect, useMemo } from 'react'
import type { CommandResultDisplay } from '../../commands.js'
import { ClaudeAuthProvider } from '../../services/mcp/auth.js'
import type {
  McpClaudeAIProxyServerConfig,
  McpHTTPServerConfig,
  McpSSEServerConfig,
  McpStdioServerConfig,
} from '../../services/mcp/types.js'
import {
  extractAgentMcpServers,
  filterToolsByServer,
} from '../../services/mcp/utils.js'
import { useAppState } from '../../state/AppState.js'
import { getSessionIngressAuthToken } from '../../utils/sessionIngressAuth.js'
import { MCPAgentServerMenu } from './MCPAgentServerMenu.js'
import { MCPListPanel } from './MCPListPanel.js'
import { MCPRemoteServerMenu } from './MCPRemoteServerMenu.js'
import { MCPStdioServerMenu } from './MCPStdioServerMenu.js'
import { MCPToolDetailView } from './MCPToolDetailView.js'
import { MCPToolListView } from './MCPToolListView.js'
import type { AgentMcpServerInfo, MCPViewState, ServerInfo } from './types.js'

type Props = {
  onComplete: (
    result?: string,
    options?: { display?: CommandResultDisplay },
  ) => void
}

export function MCPSettings({ onComplete }: Props): React.ReactNode {
  const mcp = useAppState(s => s.mcp)
  const agentDefinitions = useAppState(s => s.agentDefinitions)
  const mcpClients = mcp.clients
  const [viewState, setViewState] = React.useState<MCPViewState>({
    type: 'list',
  })
  const [servers, setServers] = React.useState<ServerInfo[]>([])

  // Extract agent-specific MCP servers from agent definitions
  const agentMcpServers = useMemo(
    () => extractAgentMcpServers(agentDefinitions.allAgents),
    [agentDefinitions.allAgents],
  )

  const filteredClients = React.useMemo(
    () =>
      mcpClients
        .filter(client => client.name !== 'ide')
        .sort((a, b) => a.name.localeCompare(b.name)),
    [mcpClients],
  )

  React.useEffect(() => {
    let cancelled = false
    async function prepareServers() {
      const serverInfos = await Promise.all(
        filteredClients.map(async client => {
          const scope = client.config.scope
          const isSSE = client.config.type === 'sse'
          const isHTTP = client.config.type === 'http'
          const isClaudeAIProxy = client.config.type === 'claudeai-proxy'
          let isAuthenticated: boolean | undefined

          if (isSSE || isHTTP) {
            const authProvider = new ClaudeAuthProvider(
              client.name,
              client.config as McpSSEServerConfig | McpHTTPServerConfig,
            )
            const tokens = await authProvider.tokens()
            // Server is authenticated if:
            // 1. It has OAuth tokens, OR
            // 2. It's connected via session auth (has session token and is connected), OR
            // 3. It's connected and has tools (meaning it's working, regardless of auth method)
            const hasSessionAuth =
              getSessionIngressAuthToken() !== null &&
              client.type === 'connected'
            const hasToolsAndConnected =
              client.type === 'connected' &&
              filterToolsByServer(mcp.tools, client.name).length > 0
            isAuthenticated =
              Boolean(tokens) || hasSessionAuth || hasToolsAndConnected
          }

          const baseInfo = {
            name: client.name,
            client,
            scope,
          }

          if (isClaudeAIProxy) {
            return {
              ...baseInfo,
              transport: 'claudeai-proxy' as const,
              isAuthenticated: false,
              config: client.config as McpClaudeAIProxyServerConfig,
            }
          } else if (isSSE) {
            return {
              ...baseInfo,
              transport: 'sse' as const,
              isAuthenticated,
              config: client.config as McpSSEServerConfig,
            }
          } else if (isHTTP) {
            return {
              ...baseInfo,
              transport: 'http' as const,
              isAuthenticated,
              config: client.config as McpHTTPServerConfig,
            }
          } else {
            return {
              ...baseInfo,
              transport: 'stdio' as const,
              config: client.config as McpStdioServerConfig,
            }
          }
        }),
      )

      if (cancelled) return
      setServers(serverInfos)
    }

    void prepareServers()
    return () => {
      cancelled = true
    }
  }, [filteredClients, mcp.tools])

  useEffect(() => {
    if (servers.length === 0 && filteredClients.length > 0) {
      // Still loading
      return
    }

    // Only show "no servers" message if no regular servers AND no agent servers
    if (servers.length === 0 && agentMcpServers.length === 0) {
      onComplete(
        'No MCP servers configured. Please run /doctor if this is unexpected. Otherwise, run `claude mcp --help` or visit https://code.claude.com/docs/en/mcp to learn more.',
      )
    }
  }, [
    servers.length,
    filteredClients.length,
    agentMcpServers.length,
    onComplete,
  ])

  switch (viewState.type) {
    case 'list':
      return (
        <MCPListPanel
          servers={servers}
          agentServers={agentMcpServers}
          onSelectServer={server =>
            setViewState({ type: 'server-menu', server })
          }
          onSelectAgentServer={(agentServer: AgentMcpServerInfo) =>
            setViewState({ type: 'agent-server-menu', agentServer })
          }
          onComplete={onComplete}
          defaultTab={viewState.defaultTab}
        />
      )

    case 'server-menu': {
      const serverTools = filterToolsByServer(mcp.tools, viewState.server.name)

      const defaultTab =
        viewState.server.transport === 'claudeai-proxy'
          ? 'claude.ai'
          : 'Claude Code'

      if (viewState.server.transport === 'stdio') {
        return (
          <MCPStdioServerMenu
            server={viewState.server}
            serverToolsCount={serverTools.length}
            onViewTools={() =>
              setViewState({ type: 'server-tools', server: viewState.server })
            }
            onCancel={() => setViewState({ type: 'list', defaultTab })}
            onComplete={onComplete}
          />
        )
      } else {
        return (
          <MCPRemoteServerMenu
            server={viewState.server}
            serverToolsCount={serverTools.length}
            onViewTools={() =>
              setViewState({ type: 'server-tools', server: viewState.server })
            }
            onCancel={() => setViewState({ type: 'list', defaultTab })}
            onComplete={onComplete}
          />
        )
      }
    }

    case 'server-tools':
      return (
        <MCPToolListView
          server={viewState.server}
          onSelectTool={(_, index) =>
            setViewState({
              type: 'server-tool-detail',
              server: viewState.server,
              toolIndex: index,
            })
          }
          onBack={() =>
            setViewState({ type: 'server-menu', server: viewState.server })
          }
        />
      )

    case 'server-tool-detail': {
      const serverTools = filterToolsByServer(mcp.tools, viewState.server.name)
      const tool = serverTools[viewState.toolIndex]
      if (!tool) {
        setViewState({ type: 'server-tools', server: viewState.server })
        return null
      }
      return (
        <MCPToolDetailView
          tool={tool}
          server={viewState.server}
          onBack={() =>
            setViewState({ type: 'server-tools', server: viewState.server })
          }
        />
      )
    }

    case 'agent-server-menu':
      return (
        <MCPAgentServerMenu
          agentServer={viewState.agentServer}
          onCancel={() => setViewState({ type: 'list', defaultTab: 'Agents' })}
          onComplete={onComplete}
        />
      )
  }
}
