import { useCanvasStore } from '../stores/canvas'
import { endpoints, isSecure, wsProtocol, hostname, resolveEndpoints } from '../config/endpoints'
import { isTauri, getServerUrl } from '@/lib/tauri'
import { apiFetch } from '@/lib/tauri'

// WebMCP HTTP API base for direct token requests (resolved dynamically for Tauri)
function getWebmcpHttp() { return resolveEndpoints().webmcpHttp }

let webmcpInstance: any = null
const registeredTools = new Set<string>()
const eventUnsubscribers: Array<() => void> = []

function getApiBase() { return resolveEndpoints().api }
let tokenPollingInterval: number | null = null

export async function initWebMCP() {
  if (webmcpInstance) return webmcpInstance

  const WebMCPModule = await import('@nucleoriofrio/webmcp/src/webmcp.js')
  const WebMCP = WebMCPModule.default || WebMCPModule

  webmcpInstance = new WebMCP({
    headless: true,
    inactivityTimeout: 60 * 60 * 1000 // 1 hora
  })

  setupEventHandlers()

  // Check initial connection state
  if (webmcpInstance.isConnected) {
    const canvasStore = useCanvasStore()
    canvasStore.setConnected(true)
    updateConnectionInfo()
  }

  // Expose globally for debug
  ;(window as any).webmcp = webmcpInstance

  return webmcpInstance
}

function setupEventHandlers() {
  // Skip if instance doesn't support events
  if (typeof webmcpInstance.on !== 'function') {
    console.warn('[WebMCP] Event emitter not available')
    return
  }

  const canvasStore = useCanvasStore()

  // Connection events
  eventUnsubscribers.push(
    webmcpInstance.on('connected', () => {
      console.log('[WebMCP] Connected')
      canvasStore.setConnected(true)
      canvasStore.setReconnecting(false)
      canvasStore.setConnectionError(null)
      updateConnectionInfo()
    })
  )

  eventUnsubscribers.push(
    webmcpInstance.on('disconnected', () => {
      console.log('[WebMCP] Disconnected')
      canvasStore.setConnected(false)
      canvasStore.setReconnecting(false)
      canvasStore.setConnectionInfo(null)
    })
  )

  eventUnsubscribers.push(
    webmcpInstance.on('reconnecting', () => {
      console.log('[WebMCP] Reconnecting...')
      canvasStore.setReconnecting(true)
    })
  )

  // Status changes
  eventUnsubscribers.push(
    webmcpInstance.on('statusChange', (data: { status: string }) => {
      canvasStore.setConnectionStatus(data.status)
    })
  )

  // Error handling
  eventUnsubscribers.push(
    webmcpInstance.on('error', (data: { message: string }) => {
      console.error('[WebMCP] Error:', data.message)
      canvasStore.setConnectionError(data.message)
      canvasStore.showNotification(data.message, 'error')
    })
  )

  // Tool events
  eventUnsubscribers.push(
    webmcpInstance.on('toolRegistered', (data: { name: string }) => {
      console.log('[WebMCP] Tool registered by server:', data.name)
      updateConnectionInfo()
    })
  )

  eventUnsubscribers.push(
    webmcpInstance.on('toolCreated', (data: { name: string }) => {
      console.log('[WebMCP] Tool created:', data.name)
      registeredTools.add(data.name)
      updateConnectionInfo()
    })
  )

  eventUnsubscribers.push(
    webmcpInstance.on('toolRemoved', (data: { name: string }) => {
      if (data.name === '*') {
        console.log('[WebMCP] All tools removed')
        registeredTools.clear()
      } else {
        console.log('[WebMCP] Tool removed:', data.name)
        registeredTools.delete(data.name)
      }
      updateConnectionInfo()
    })
  )
}

function updateConnectionInfo() {
  if (!webmcpInstance) return

  const canvasStore = useCanvasStore()
  const info = webmcpInstance.getConnectionInfo?.()

  if (info) {
    canvasStore.setConnectionInfo({
      isConnected: info.isConnected,
      channel: info.channel,
      server: info.server,
      status: info.status,
      tools: info.tools || [],
      prompts: info.prompts || [],
      resources: info.resources || []
    })
  }
}

export function getConnectionInfo() {
  return webmcpInstance?.getConnectionInfo?.() || null
}

export function getWebMCP() {
  return webmcpInstance
}

export function registerTool(
  name: string,
  description: string,
  schema: object,
  handler: Function
) {
  if (!webmcpInstance) {
    console.warn('[WebMCP] Instance not initialized')
    return false
  }
  if (registeredTools.has(name)) {
    console.warn(`[WebMCP] Tool "${name}" already registered, skipping`)
    return false
  }
  webmcpInstance.registerTool(name, description, schema, handler)
  registeredTools.add(name)
  console.log(`[WebMCP] Tool registered: ${name}`)
  return true
}

export function unregisterTool(name: string) {
  if (!webmcpInstance) {
    console.warn('[WebMCP] Instance not initialized')
    return false
  }
  if (!registeredTools.has(name)) {
    return false
  }
  webmcpInstance.unregisterTool(name)
  registeredTools.delete(name)
  console.log(`[WebMCP] Tool unregistered: ${name}`)
  return true
}

export function unregisterTools(names: string[]) {
  for (const name of names) {
    unregisterTool(name)
  }
}

export function clearAllTools() {
  if (!webmcpInstance) return
  for (const name of registeredTools) {
    webmcpInstance.unregisterTool(name)
  }
  console.log(`[WebMCP] Cleared ${registeredTools.size} tools`)
  registeredTools.clear()
  // Clear session storage to prevent stale schemas on reconnect
  if (typeof webmcpInstance._clearStoredItems === 'function') {
    webmcpInstance._clearStoredItems()
  }
}

/**
 * Disconnect from WebMCP without destroying the instance
 * Used when losing the torch to another browser
 */
export function disconnectWebMCP(): void {
  if (!webmcpInstance) {
    console.warn('[WebMCP] Instance not initialized')
    return
  }

  if (!webmcpInstance.isConnected) {
    console.log('[WebMCP] Already disconnected')
    return
  }

  if (typeof webmcpInstance.disconnect === 'function') {
    console.log('[WebMCP] Disconnecting...')
    webmcpInstance.disconnect()

    // Update store immediately (event handler will also fire)
    const canvasStore = useCanvasStore()
    canvasStore.setConnected(false)
    canvasStore.setConnectionInfo(null)
  } else {
    console.warn('[WebMCP] disconnect method not available')
  }
}

export function destroyWebMCP() {
  // Unsubscribe all event handlers
  for (const unsub of eventUnsubscribers) {
    unsub()
  }
  eventUnsubscribers.length = 0

  // Clear tools
  clearAllTools()

  // Disconnect if connected
  if (webmcpInstance?.disconnect) {
    webmcpInstance.disconnect()
  }

  webmcpInstance = null
  ;(window as any).webmcp = null
  console.log('[WebMCP] Instance destroyed')
}

export function getRegisteredTools(): string[] {
  return [...registeredTools]
}

export function isToolRegistered(name: string): boolean {
  return registeredTools.has(name)
}

// Token polling functions
export async function checkForToken(): Promise<string | null> {
  try {
    const res = await apiFetch(`${getApiBase()}/webmcp-token`)
    const data = await res.json()
    return data.token || null
  } catch (e) {
    return null
  }
}

export async function clearToken(): Promise<void> {
  try {
    await apiFetch(`${getApiBase()}/webmcp-token`, { method: 'DELETE' })
  } catch (e) {
    // ignore
  }
}

export function startTokenPolling(onToken: (token: string) => void, intervalMs: number = 2000) {
  if (tokenPollingInterval) return

  console.log('[WebMCP] Starting token polling...')
  tokenPollingInterval = window.setInterval(async () => {
    const token = await checkForToken()
    if (token) {
      console.log('[WebMCP] Token detected!')
      stopTokenPolling()
      onToken(token)
    }
  }, intervalMs)
}

export function stopTokenPolling() {
  if (tokenPollingInterval) {
    window.clearInterval(tokenPollingInterval)
    tokenPollingInterval = null
    console.log('[WebMCP] Token polling stopped')
  }
}

export function parseToken(token: string): { server: string; token: string } | null {
  try {
    const decoded = atob(token)
    return JSON.parse(decoded)
  } catch (e) {
    console.error('[WebMCP] Failed to parse token:', e)
    return null
  }
}

/**
 * Request a new token directly from WebMCP server via HTTP API
 * In development: calls WebMCP directly at port 4102
 * In production (HTTPS): calls Agent UI API which proxies to WebMCP
 */
export async function requestToken(): Promise<string | null> {
  try {
    console.log('[WebMCP] Requesting token from server...')

    // In HTTPS or Tauri mode, use Agent UI API as proxy
    // In development, call WebMCP directly
    const url = (isSecure || isTauri) ? `${getApiBase()}/webmcp-request-token` : `${getWebmcpHttp()}/token`

    const res = await apiFetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' }
    })

    if (!res.ok) {
      console.error('[WebMCP] Failed to request token:', res.status)
      return null
    }

    // Check if response is JSON
    const contentType = res.headers.get('content-type')
    if (!contentType?.includes('application/json')) {
      console.warn('[WebMCP] /token endpoint not available (server returned non-JSON)')
      return null
    }

    const data = await res.json()
    if (data.success && data.token) {
      console.log('[WebMCP] Token received from server')
      return data.token
    }
    return null
  } catch (e) {
    // Network error or endpoint not available
    console.warn('[WebMCP] /token endpoint not available:', (e as Error).message)
    return null
  }
}

/**
 * Auto-connect to WebMCP by requesting a token and connecting
 * Returns true if connection was successful
 */
export async function autoConnect(): Promise<boolean> {
  if (!webmcpInstance) {
    console.error('[WebMCP] Instance not initialized, call initWebMCP() first')
    return false
  }

  // Check if already connected
  if (webmcpInstance.isConnected) {
    console.log('[WebMCP] Already connected')
    return true
  }

  // Request token from server
  const token = await requestToken()
  if (!token) {
    console.error('[WebMCP] Failed to get token')
    return false
  }

  // Connect with the token
  return connectWithToken(token)
}

export async function connectWithToken(token: string): Promise<boolean> {
  if (!webmcpInstance) {
    console.error('[WebMCP] Instance not initialized')
    return false
  }

  if (typeof webmcpInstance.connect !== 'function') {
    console.error('[WebMCP] connect method not available')
    return false
  }

  console.log('[WebMCP] Connecting with token...')

  // Clear the pending token from server
  await clearToken()

  // Modify token for correct WebSocket URL based on environment
  let finalToken = token
  if (isTauri) {
    // In Tauri, rewrite WebSocket URL to match configured server
    const parsed = parseToken(token)
    if (parsed) {
      const wsUrl = resolveEndpoints().webmcp
      const modifiedToken = { server: wsUrl, token: parsed.token }
      finalToken = btoa(JSON.stringify(modifiedToken))
      console.log('[WebMCP] Modified token for Tauri:', wsUrl)
    }
  } else if (isSecure) {
    const parsed = parseToken(token)
    if (parsed) {
      // Replace ws://localhost:4102 with wss://hostname/ws/mcp
      const secureServer = `${wsProtocol}//${hostname}/ws/mcp`
      const modifiedToken = { server: secureServer, token: parsed.token }
      finalToken = btoa(JSON.stringify(modifiedToken))
      console.log('[WebMCP] Modified token for HTTPS:', secureServer)
    }
  }

  // Connect passing the token directly
  try {
    await webmcpInstance.connect(finalToken)

    // Wait for connection to be fully established (event handler updates store)
    const connected = await waitForConnection(3000)
    if (!connected) {
      console.warn('[WebMCP] Connection timeout - store not updated')
    }
    return connected
  } catch (e) {
    console.error('[WebMCP] Failed to connect:', e)
    return false
  }
}

/**
 * Wait for isConnected to become true
 */
async function waitForConnection(timeoutMs: number = 3000): Promise<boolean> {
  const canvasStore = useCanvasStore()

  // Already connected
  if (canvasStore.isConnected) {
    return true
  }

  // Wait for connection with polling
  const startTime = Date.now()
  while (Date.now() - startTime < timeoutMs) {
    await new Promise(resolve => setTimeout(resolve, 100))
    if (canvasStore.isConnected) {
      console.log('[WebMCP] Connection confirmed')
      return true
    }
  }

  return false
}
