'use client'

import React, { useState, useCallback, useEffect, useRef, useMemo } from 'react'
import Editor, { type OnMount } from '@monaco-editor/react'
import type { editor } from 'monaco-editor'
import { 
  File, 
  Folder, 
  FolderOpen, 
  X, 
  FloppyDisk,
  CaretRight,
  CaretDown,
  Spinner,
  Plus,
  Minus,
  Eye,
  Code,
  Trash,
  ArrowsOut,
  ArrowClockwise,
} from '@phosphor-icons/react'
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from '@/components/ui/tooltip'
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
import { 
  useModeContext, 
  useWorkspace,
  useNotes,
  useEditorState,
  getMonacoLanguage,
  getFileType,
  supportsPreview,
  type NoteFile,
} from '@/lib/api-docs/code-editor'

// VSCode-style file icon with color coding
function FileIcon({ path, className }: { path: string; className?: string }) {
  const type = getFileType(path)
  
  const colorMap: Record<string, string> = {
    'javascript': 'text-yellow-400',
    'typescript': 'text-blue-400',
    'python': 'text-green-500',
    'go': 'text-cyan-400',
    'ruby': 'text-red-400',
    'php': 'text-purple-400',
    'shell': 'text-green-400',
    'markdown': 'text-blue-300',
    'mermaid': 'text-pink-400',
    'json': 'text-yellow-500',
    'yaml': 'text-red-300',
    'text': 'text-zinc-400',
  }
  
  return (
    <File className={cn('h-4 w-4 flex-shrink-0', colorMap[type] || 'text-zinc-400', className)} weight="fill" />
  )
}

// Build tree from flat file list
interface TreeNode {
  name: string
  path: string
  isFolder: boolean
  children?: TreeNode[]
  file?: NoteFile
}

function buildFileTree(files: NoteFile[]): TreeNode[] {
  const root: TreeNode[] = []
  
  // Filter out .folder placeholder files - they're only used internally to create folder structure
  const visibleFiles = files.filter(f => !f.path.endsWith('.folder') && !f.path.includes('/.folder'))
  const sortedFiles = [...visibleFiles].sort((a, b) => a.path.localeCompare(b.path))
  
  for (const file of sortedFiles) {
    const parts = file.path.split('/')
    let current = root
    
    for (let i = 0; i < parts.length; i++) {
      const part = parts[i]
      const isLastPart = i === parts.length - 1
      const currentPath = parts.slice(0, i + 1).join('/')
      
      let existing = current.find(n => n.name === part)
      
      if (!existing) {
        existing = {
          name: part,
          path: currentPath,
          isFolder: !isLastPart,
          children: isLastPart ? undefined : [],
          file: isLastPart ? file : undefined,
        }
        current.push(existing)
      }
      
      if (!isLastPart && existing.children) {
        current = existing.children
      }
    }
  }
  
  // Sort: folders first, then alphabetically
  const sortNodes = (nodes: TreeNode[]): TreeNode[] => {
    return nodes.sort((a, b) => {
      if (a.isFolder !== b.isFolder) return a.isFolder ? -1 : 1
      return a.name.localeCompare(b.name)
    }).map(node => ({
      ...node,
      children: node.children ? sortNodes(node.children) : undefined,
    }))
  }
  
  return sortNodes(root)
}

// File tree item component
interface FileTreeItemProps {
  node: TreeNode
  depth: number
  activeFile: string | null
  expandedFolders: Set<string>
  onFileClick: (path: string) => void
  onFolderToggle: (path: string) => void
  onDelete?: (path: string) => void
}

function FileTreeItem({ 
  node, 
  depth, 
  activeFile, 
  expandedFolders, 
  onFileClick, 
  onFolderToggle,
  onDelete,
}: FileTreeItemProps) {
  const isExpanded = expandedFolders.has(node.path)
  const isActive = activeFile === node.path
  const [showContextMenu, setShowContextMenu] = useState<{ x: number; y: number } | null>(null)
  
  // Close context menu
  useEffect(() => {
    if (showContextMenu) {
      const handleClick = () => setShowContextMenu(null)
      const handleKeyDown = (e: KeyboardEvent) => {
        if (e.key === 'Escape') setShowContextMenu(null)
      }
      document.addEventListener('click', handleClick)
      document.addEventListener('keydown', handleKeyDown)
      return () => {
        document.removeEventListener('click', handleClick)
        document.removeEventListener('keydown', handleKeyDown)
      }
    }
  }, [showContextMenu])
  
  const handleClick = (e: React.MouseEvent) => {
    e.preventDefault()
    if (node.isFolder) {
      onFolderToggle(node.path)
    } else {
      onFileClick(node.path)
    }
  }
  
  const handleContextMenu = (e: React.MouseEvent) => {
    e.preventDefault()
    setShowContextMenu({ x: e.clientX, y: e.clientY })
  }
  
  return (
    <div className="relative">
      <button
        onClick={handleClick}
        onContextMenu={handleContextMenu}
        className={cn(
          'w-full flex items-center gap-1 text-[13px] text-left transition-colors group',
          isActive && 'sandbox-file-active',
          !isActive && 'sandbox-file-hover',
        )}
        style={{ 
          height: '22px',
          paddingLeft: `${depth * 8 + 4}px`,
          paddingRight: '8px',
        }}
      >
        <span className="w-4 h-4 flex items-center justify-center flex-shrink-0">
          {node.isFolder && (
            isExpanded ? (
              <CaretDown className="h-3 w-3 text-zinc-400" weight="bold" />
            ) : (
              <CaretRight className="h-3 w-3 text-zinc-400" weight="bold" />
            )
          )}
        </span>
        
        {node.isFolder ? (
          isExpanded ? (
            <FolderOpen className="h-4 w-4 text-amber-400 flex-shrink-0" weight="fill" />
          ) : (
            <Folder className="h-4 w-4 text-amber-400 flex-shrink-0" weight="fill" />
          )
        ) : (
          <FileIcon path={node.path} />
        )}
        
        <span className={cn(
          'truncate ml-1',
          isActive && 'text-white',
          !isActive && 'text-zinc-300',
        )}>
          {node.name}
        </span>
      </button>
      
      {/* Context menu */}
      {showContextMenu && !node.isFolder && (
        <div 
          className="fixed z-50 min-w-[140px] py-1 sandbox-context-menu rounded shadow-xl"
          style={{ left: showContextMenu.x, top: showContextMenu.y }}
          onClick={(e) => e.stopPropagation()}
        >
          <button
            onClick={() => { onDelete?.(node.path); setShowContextMenu(null) }}
            className="w-full flex items-center gap-2 px-3 py-1.5 text-[13px] sandbox-context-menu-delete text-left"
          >
            <Trash className="h-4 w-4" />
            Delete
          </button>
        </div>
      )}
      
      {node.isFolder && isExpanded && node.children && (
        <div>
          {node.children.map(child => (
            <FileTreeItem
              key={child.path}
              node={child}
              depth={depth + 1}
              activeFile={activeFile}
              expandedFolders={expandedFolders}
              onFileClick={onFileClick}
              onFolderToggle={onFolderToggle}
              onDelete={onDelete}
            />
          ))}
        </div>
      )}
    </div>
  )
}

// Editor tabs
function EditorTabs({ 
  tabs, 
  activeTab, 
  onTabClick, 
  onTabClose 
}: { 
  tabs: string[]
  activeTab: string | null
  onTabClick: (path: string) => void
  onTabClose: (path: string) => void
}) {
  if (tabs.length === 0) return null
  
  return (
    <div className="flex items-center h-[35px] sandbox-tabs overflow-x-auto">
      {tabs.map(path => {
        const fileName = path.split('/').pop() || path
        const isActive = path === activeTab
        
        return (
          <div
            key={path}
            className={cn(
              'relative flex items-center gap-1.5 px-3 h-full text-[13px] cursor-pointer group min-w-0',
              isActive ? 'sandbox-tab-active' : 'sandbox-tab-inactive',
            )}
            onClick={() => onTabClick(path)}
          >
            {isActive && <div className="absolute top-0 left-0 right-0 h-[2px] sandbox-tab-indicator" />}
            <FileIcon path={path} className="h-4 w-4 flex-shrink-0" />
            <span className="truncate">{fileName}</span>
            <button
              onClick={(e) => { e.stopPropagation(); onTabClose(path) }}
              className={cn(
                'p-0.5 rounded flex-shrink-0 ml-1 sandbox-tab-close',
                isActive ? '' : 'opacity-0 group-hover:opacity-100',
              )}
            >
              <X className="h-3 w-3" />
            </button>
          </div>
        )
      })}
      <div className="flex-1 h-full sandbox-tabs" />
    </div>
  )
}

// Note type templates
const noteTemplates = [
  { 
    ext: '.py', 
    name: 'Python', 
    color: 'text-green-400', 
    bg: 'bg-green-500/10 hover:bg-green-500/20 border-green-500/30',
    desc: 'Python script'
  },
  { 
    ext: '.ts', 
    name: 'TypeScript', 
    color: 'text-blue-400', 
    bg: 'bg-blue-500/10 hover:bg-blue-500/20 border-blue-500/30',
    desc: 'TypeScript code'
  },
  { 
    ext: '.js', 
    name: 'JavaScript', 
    color: 'text-yellow-400', 
    bg: 'bg-yellow-500/10 hover:bg-yellow-500/20 border-yellow-500/30',
    desc: 'JavaScript code'
  },
  { 
    ext: '.md', 
    name: 'Markdown', 
    color: 'text-blue-300', 
    bg: 'bg-blue-400/10 hover:bg-blue-400/20 border-blue-400/30',
    desc: 'Documentation'
  },
  { 
    ext: '.mmd', 
    name: 'Mermaid', 
    color: 'text-pink-400', 
    bg: 'bg-pink-500/10 hover:bg-pink-500/20 border-pink-500/30',
    desc: 'Diagrams'
  },
  { 
    ext: '.json', 
    name: 'JSON', 
    color: 'text-yellow-500', 
    bg: 'bg-yellow-500/10 hover:bg-yellow-500/20 border-yellow-500/30',
    desc: 'Data/Config'
  },
  { 
    ext: '.go', 
    name: 'Go', 
    color: 'text-cyan-400', 
    bg: 'bg-cyan-500/10 hover:bg-cyan-500/20 border-cyan-500/30',
    desc: 'Go code'
  },
  { 
    ext: '.rb', 
    name: 'Ruby', 
    color: 'text-red-400', 
    bg: 'bg-red-500/10 hover:bg-red-500/20 border-red-500/30',
    desc: 'Ruby script'
  },
]

// New file dialog - VSCode style command palette
function NewNoteDialog({ 
  open, 
  onOpenChange, 
  onCreateNote 
}: { 
  open: boolean
  onOpenChange: (open: boolean) => void
  onCreateNote: (path: string) => void
}) {
  const [fileName, setFileName] = useState('')
  const [selectedTemplate, setSelectedTemplate] = useState<typeof noteTemplates[0] | null>(null)
  const inputRef = useRef<HTMLInputElement>(null)
  
  // Reset on open
  useEffect(() => {
    if (open) {
      setFileName('')
      setSelectedTemplate(null)
      setTimeout(() => inputRef.current?.focus(), 50)
    }
  }, [open])
  
  // Detect file type from name
  const detectedType = useMemo(() => {
    const ext = fileName.match(/\.[^.]+$/)?.[0]
    return noteTemplates.find(t => t.ext === ext) || null
  }, [fileName])
  
  const handleCreate = () => {
    if (!fileName.trim()) return
    let finalName = fileName.trim()
    
    // Add extension if not present and template selected
    if (selectedTemplate && !finalName.includes('.')) {
      finalName += selectedTemplate.ext
    }
    
    onCreateNote(finalName)
    setFileName('')
    setSelectedTemplate(null)
    onOpenChange(false)
  }
  
  const handleTemplateClick = (template: typeof noteTemplates[0]) => {
    setSelectedTemplate(template)
    // Update file name with new extension
    const baseName = fileName.replace(/\.[^.]+$/, '') || 'untitled'
    setFileName(baseName + template.ext)
    inputRef.current?.focus()
  }
  
  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && fileName.trim()) {
      handleCreate()
    }
    if (e.key === 'Escape') {
      onOpenChange(false)
    }
  }
  
  const activeTemplate = detectedType || selectedTemplate
  
  if (!open) return null
  
  return (
    <div className="fixed inset-0 z-50 flex items-start justify-center pt-[15vh]">
      {/* Backdrop */}
      <div 
        className="absolute inset-0 bg-black/50" 
        onClick={() => onOpenChange(false)}
      />
      
      {/* Dialog */}
      <div className="relative w-full max-w-lg mx-4 bg-[#1e1e1e] border border-[#454545] rounded-lg shadow-2xl overflow-hidden">
        {/* Input area */}
        <div className="flex items-center gap-3 p-3 border-b border-[#3c3c3c]">
          <div className={cn(
            "w-8 h-8 rounded flex items-center justify-center flex-shrink-0 transition-colors",
            activeTemplate ? activeTemplate.bg : "bg-[#2d2d2d]"
          )}>
            <File className={cn("h-4 w-4", activeTemplate?.color || "text-zinc-400")} weight="fill" />
          </div>
          <input
            ref={inputRef}
            type="text"
            value={fileName}
            onChange={(e) => setFileName(e.target.value)}
            onKeyDown={handleKeyDown}
            placeholder="Enter file name..."
            className="flex-1 bg-transparent text-sm text-zinc-100 placeholder:text-zinc-500 outline-none"
          />
          {fileName.trim() && (
            <button
              onClick={handleCreate}
              className="px-3 py-1.5 text-xs font-medium bg-[#007acc] hover:bg-[#006bb3] text-white rounded transition-colors"
            >
              Create
            </button>
          )}
        </div>
        
        {/* Type selection grid */}
        <div className="p-3">
          <p className="text-[11px] uppercase tracking-wider text-zinc-500 mb-2 px-1">
            Select type
          </p>
          <div className="grid grid-cols-4 gap-2">
            {noteTemplates.map((template) => {
              const isActive = activeTemplate?.ext === template.ext
              return (
                <button
                  key={template.ext}
                  onClick={() => handleTemplateClick(template)}
                  className={cn(
                    "flex flex-col items-center gap-1.5 p-3 rounded-lg border transition-all",
                    isActive 
                      ? `${template.bg} border-current` 
                      : "bg-[#2d2d2d] border-[#3c3c3c] hover:bg-[#333333] hover:border-[#4c4c4c]"
                  )}
                >
                  <File className={cn("h-5 w-5", template.color)} weight="fill" />
                  <span className={cn(
                    "text-[11px] font-medium",
                    isActive ? template.color : "text-zinc-300"
                  )}>
                    {template.name}
                  </span>
                </button>
              )
            })}
          </div>
        </div>
        
        {/* Tips */}
        <div className="px-4 py-2.5 bg-[#252526] border-t border-[#3c3c3c] flex items-center justify-between">
          <p className="text-[11px] text-zinc-500">
            Tip: Use <code className="px-1 py-0.5 bg-[#3c3c3c] rounded text-zinc-400">folder/file.ext</code> for nested files
          </p>
          <div className="flex items-center gap-2 text-[11px] text-zinc-500">
            <span className="px-1.5 py-0.5 bg-[#3c3c3c] rounded text-[10px]">↵</span>
            <span>Create</span>
            <span className="px-1.5 py-0.5 bg-[#3c3c3c] rounded text-[10px]">Esc</span>
            <span>Cancel</span>
          </div>
        </div>
      </div>
    </div>
  )
}

// Error Boundary for Mermaid Preview
class MermaidErrorBoundary extends React.Component<
  { children: React.ReactNode; code: string },
  { hasError: boolean; error: string | null }
> {
  constructor(props: { children: React.ReactNode; code: string }) {
    super(props)
    this.state = { hasError: false, error: null }
  }

  static getDerivedStateFromError(error: Error) {
    return { hasError: true, error: error.message }
  }

  componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
    console.error('[MermaidErrorBoundary] Error:', error, errorInfo)
  }

  // Reset error when code changes
  componentDidUpdate(prevProps: { code: string }) {
    if (prevProps.code !== this.props.code && this.state.hasError) {
      this.setState({ hasError: false, error: null })
    }
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="flex flex-col items-center justify-center h-full text-zinc-400 text-sm p-4 gap-4">
          <p className="text-red-400">Render Error: {this.state.error}</p>
          <div className="w-full max-w-lg">
            <p className="text-xs text-zinc-500 mb-2">Source:</p>
            <pre className="p-4 bg-[#2d2d2d] rounded text-xs overflow-auto max-h-[200px] text-zinc-300">
              {this.props.code}
            </pre>
          </div>
        </div>
      )
    }
    return this.props.children
  }
}

// Mermaid preview component with zoom/pan
function MermaidPreviewInner({ code }: { code: string }) {
  const containerRef = useRef<HTMLDivElement>(null)
  const contentRef = useRef<HTMLDivElement>(null)
  const [svg, setSvg] = useState<string>('')
  const [error, setError] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const renderIdRef = useRef(0)
  
  // Zoom and pan state
  const [scale, setScale] = useState(1)
  const [position, setPosition] = useState({ x: 0, y: 0 })
  const [isDragging, setIsDragging] = useState(false)
  const dragStart = useRef({ x: 0, y: 0 })
  const positionStart = useRef({ x: 0, y: 0 })
  
  useEffect(() => {
    if (!code.trim()) {
      setLoading(false)
      setSvg('')
      setError(null)
      return
    }
    
    const currentRenderId = ++renderIdRef.current
    setLoading(true)
    setError(null)
    
    const renderDiagram = async () => {
      try {
        const mermaid = (await import('mermaid')).default
        
        mermaid.initialize({ 
          startOnLoad: false, 
          theme: 'dark',
          themeVariables: {
            // Force dark backgrounds everywhere
            background: '#1e1e1e',
            primaryColor: '#3b82f6',
            primaryTextColor: '#ffffff',
            primaryBorderColor: '#60a5fa',
            secondaryColor: '#3b82f6',
            secondaryTextColor: '#ffffff', 
            secondaryBorderColor: '#60a5fa',
            tertiaryColor: '#3b82f6',
            tertiaryTextColor: '#ffffff',
            tertiaryBorderColor: '#60a5fa',
            
            // Node backgrounds - force blue
            mainBkg: '#3b82f6',
            nodeBkg: '#3b82f6',
            nodeBorder: '#60a5fa',
            nodeTextColor: '#ffffff',
            
            // Cluster styling
            clusterBkg: '#27272a',
            clusterBorder: '#52525b',
            titleColor: '#ffffff',
            
            // Lines
            lineColor: '#94a3b8',
            
            // Font
            fontFamily: 'system-ui, sans-serif',
            fontSize: '14px',
          },
          flowchart: {
            htmlLabels: true,
            useMaxWidth: true,
          }
        })
        
        // Use unique ID to avoid conflicts
        const { svg: renderedSvg } = await mermaid.render(`mermaid-${currentRenderId}-${Date.now()}`, code)
        
        // Only update if this is still the latest render
        if (currentRenderId === renderIdRef.current) {
          setSvg(renderedSvg)
          setError(null)
          // Reset zoom/pan when diagram changes
          setScale(1)
          setPosition({ x: 0, y: 0 })
        }
      } catch (err: unknown) {
        if (currentRenderId === renderIdRef.current) {
          // Extract meaningful error message from mermaid errors
          let errorMessage = 'Failed to render diagram'
          if (err instanceof Error) {
            // Mermaid errors often have detailed messages
            errorMessage = err.message
            // Clean up common mermaid error prefixes
            if (errorMessage.includes('Parse error')) {
              const match = errorMessage.match(/Parse error on line (\d+)/)
              if (match) {
                errorMessage = `Syntax error on line ${match[1]}`
              }
            }
          } else if (typeof err === 'string') {
            errorMessage = err
          } else if (err && typeof err === 'object' && 'str' in err) {
            // Mermaid sometimes returns {str: "error message"}
            errorMessage = String((err as { str: unknown }).str)
          }
          setError(errorMessage)
          setSvg('') // Clear any previous SVG
        }
      } finally {
        if (currentRenderId === renderIdRef.current) {
          setLoading(false)
        }
      }
    }
    
    // Debounce rendering
    const timer = setTimeout(renderDiagram, 300)
    return () => clearTimeout(timer)
  }, [code])
  
  // Handle mouse wheel zoom
  const handleWheel = useCallback((e: React.WheelEvent) => {
    e.preventDefault()
    const delta = e.deltaY > 0 ? -0.1 : 0.1
    setScale(prev => Math.min(Math.max(0.25, prev + delta), 3))
  }, [])
  
  // Handle mouse down for pan
  const handleMouseDown = useCallback((e: React.MouseEvent) => {
    if (e.button !== 0) return // Only left click
    setIsDragging(true)
    dragStart.current = { x: e.clientX, y: e.clientY }
    positionStart.current = position
  }, [position])
  
  // Handle mouse move for pan
  const handleMouseMove = useCallback((e: React.MouseEvent) => {
    if (!isDragging) return
    const dx = e.clientX - dragStart.current.x
    const dy = e.clientY - dragStart.current.y
    setPosition({
      x: positionStart.current.x + dx,
      y: positionStart.current.y + dy
    })
  }, [isDragging])
  
  // Handle mouse up
  const handleMouseUp = useCallback(() => {
    setIsDragging(false)
  }, [])
  
  // Handle zoom controls
  const zoomIn = useCallback(() => setScale(prev => Math.min(prev + 0.25, 3)), [])
  const zoomOut = useCallback(() => setScale(prev => Math.max(prev - 0.25, 0.25)), [])
  const resetView = useCallback(() => {
    setScale(1)
    setPosition({ x: 0, y: 0 })
  }, [])
  
  if (loading) {
    return (
      <div className="flex items-center justify-center h-full text-zinc-500 text-sm">
        <Spinner className="h-5 w-5 animate-spin mr-2" />
        Rendering diagram...
      </div>
    )
  }
  
  if (error) {
    return (
      <div className="flex flex-col items-center justify-center h-full text-zinc-400 text-sm p-4 gap-4">
        <p className="text-red-400">Syntax Error: {error}</p>
        <div className="w-full max-w-lg">
          <p className="text-xs text-zinc-500 mb-2">Source:</p>
          <pre className="p-4 bg-[#2d2d2d] rounded text-xs overflow-auto max-h-[200px] text-zinc-300">
            {code}
          </pre>
        </div>
      </div>
    )
  }
  
  return (
    <div className="relative h-full w-full bg-[#1e1e1e]">
      {/* Zoom controls */}
      <div className="absolute top-3 right-3 z-10 flex items-center gap-1 bg-[#2d2d2d] rounded-md border border-[#3c3c3c] p-1">
        <button
          onClick={zoomOut}
          className="p-1.5 hover:bg-[#3c3c3c] rounded text-zinc-400 hover:text-zinc-200 transition-colors"
          title="Zoom out"
        >
          <Minus className="h-4 w-4" />
        </button>
        <span className="text-xs text-zinc-400 min-w-[3rem] text-center">{Math.round(scale * 100)}%</span>
        <button
          onClick={zoomIn}
          className="p-1.5 hover:bg-[#3c3c3c] rounded text-zinc-400 hover:text-zinc-200 transition-colors"
          title="Zoom in"
        >
          <Plus className="h-4 w-4" />
        </button>
        <div className="w-px h-4 bg-[#3c3c3c] mx-1" />
        <button
          onClick={resetView}
          className="p-1.5 hover:bg-[#3c3c3c] rounded text-zinc-400 hover:text-zinc-200 transition-colors"
          title="Reset view"
        >
          <ArrowsOut className="h-4 w-4" />
        </button>
      </div>
      
      {/* Diagram container with zoom/pan */}
      <div 
        ref={containerRef}
        className="h-full w-full overflow-hidden cursor-grab active:cursor-grabbing"
        onWheel={handleWheel}
        onMouseDown={handleMouseDown}
        onMouseMove={handleMouseMove}
        onMouseUp={handleMouseUp}
        onMouseLeave={handleMouseUp}
      >
        <div
          ref={contentRef}
          className="h-full w-full flex items-center justify-center [&_svg]:max-w-none"
          style={{
            transform: `translate(${position.x}px, ${position.y}px) scale(${scale})`,
            transformOrigin: 'center center',
            transition: isDragging ? 'none' : 'transform 0.1s ease-out'
          }}
          dangerouslySetInnerHTML={{ __html: svg }}
        />
      </div>
      
      {/* Help hint */}
      <div className="absolute bottom-3 left-3 text-[10px] text-zinc-600">
        Scroll to zoom • Drag to pan
      </div>
    </div>
  )
}

// Mermaid preview with error boundary wrapper
function MermaidPreview({ code }: { code: string }) {
  return (
    <MermaidErrorBoundary code={code}>
      <MermaidPreviewInner code={code} />
    </MermaidErrorBoundary>
  )
}

// Main Notes Mode component
export function NotesMode({ apiSpecUrl, apiName }: { apiSpecUrl: string; apiName: string }) {
  const { activeFilePath, setActiveFilePath, streamingContent, setStreamingContent, notesRefreshTrigger } = useModeContext()
  const { workspace, loading: workspaceLoading } = useWorkspace(apiSpecUrl, apiName)
  const { notes, loading: notesLoading, createNote, readNote, updateNote, deleteNote, refresh } = useNotes(workspace?.id || null)
  const { state: editorState, openTab, closeTab, setActiveTab, clearAllTabs } = useEditorState(workspace?.id || null)
  
  // Editor refs
  const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null)
  
  // Local state
  const [fileContent, setFileContent] = useState('')
  const [isModified, setIsModified] = useState(false)
  const [isSaving, setIsSaving] = useState(false)
  const [isLoadingContent, setIsLoadingContent] = useState(false)
  const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set())
  const [showNewNote, setShowNewNote] = useState(false)
  const [showPreview, setShowPreview] = useState(false)
  
  // Build file tree
  const fileTree = useMemo(() => buildFileTree(notes), [notes])
  
  // Refresh notes when triggered by agent (delete, update operations)
  useEffect(() => {
    if (notesRefreshTrigger > 0) {
      refresh()
    }
  }, [notesRefreshTrigger, refresh])
  
  // Clear tabs when all notes are deleted
  useEffect(() => {
    if (!notesLoading && notes.length === 0 && editorState?.openTabs && editorState.openTabs.length > 0) {
      clearAllTabs()
      setFileContent('')
    }
  }, [notes.length, notesLoading, editorState?.openTabs, clearAllTabs])
  
  // State validation: Clean up orphaned tabs (pointing to deleted files)
  useEffect(() => {
    if (notesLoading || !editorState?.openTabs || editorState.openTabs.length === 0) return
    
    const notePaths = new Set(notes.map(n => n.path))
    const orphanedTabs = editorState.openTabs.filter(tab => !notePaths.has(tab))
    
    if (orphanedTabs.length > 0) {
      console.log('[NotesMode] Cleaning up orphaned tabs:', orphanedTabs)
      // Close each orphaned tab
      orphanedTabs.forEach(tab => closeTab(tab))
    }
  }, [notes, notesLoading, editorState?.openTabs, closeTab])
  
  // State validation: Clear stuck streaming state (no active streaming after 30s)
  useEffect(() => {
    if (!streamingContent?.isStreaming) return
    
    const timeout = setTimeout(() => {
      if (streamingContent?.isStreaming) {
        console.log('[NotesMode] Clearing stuck streaming state')
        setStreamingContent(null)
      }
    }, 30000) // 30 second timeout
    
    return () => clearTimeout(timeout)
  }, [streamingContent?.isStreaming, setStreamingContent])
  
  // Load file content when active tab changes
  useEffect(() => {
    if (!editorState?.activeTab) {
      setFileContent('')
      setIsLoadingContent(false)
      return
    }
    
    setIsLoadingContent(true)
    const loadContent = async () => {
      const content = await readNote(editorState.activeTab!)
      setFileContent(content)
      setIsModified(false)
      setIsLoadingContent(false)
    }
    
    loadContent()
  }, [editorState?.activeTab, readNote])
  
  // Track last processed path to avoid re-processing
  const lastProcessedPath = useRef<string | null>(null)
  
  // Handle file navigation from agent
  useEffect(() => {
    if (activeFilePath && workspace) {
      // Strip timestamp from path if present (used to force refresh)
      const cleanPath = activeFilePath.split('?')[0]
      const hasTimestamp = activeFilePath.includes('?t=')
      
      // Skip if we've already processed this path (unless it has a timestamp for force refresh)
      if (lastProcessedPath.current === cleanPath && !hasTimestamp) {
        return
      }
      lastProcessedPath.current = cleanPath
      
      // Refresh notes first to ensure file is in the list
      refresh().then(async () => {
        openTab(cleanPath)
        
        // Auto-enable preview for mermaid files
        if (cleanPath.endsWith('.mmd')) {
          setShowPreview(true)
        }
        
        // If this was a write operation (has timestamp), force content reload
        if (hasTimestamp) {
          setIsLoadingContent(true)
          const content = await readNote(cleanPath)
          setFileContent(content)
          setIsModified(false)
          setIsLoadingContent(false)
          // Clear streaming content after file is loaded (prevents flash of empty content)
          if (streamingContent?.path === cleanPath) {
            setStreamingContent(null)
          }
        }
        
        // Expand parent folders
        const parts = cleanPath.split('/')
        if (parts.length > 1) {
          const foldersToExpand = parts.slice(0, -1).map((_, i) => 
            parts.slice(0, i + 1).join('/')
          )
          setExpandedFolders(prev => {
            const next = new Set(prev)
            foldersToExpand.forEach(f => next.add(f))
            return next
          })
        }
      })
    }
  }, [activeFilePath, workspace, openTab, refresh, readNote, streamingContent, setStreamingContent])
  
  // Handle folder toggle
  const handleFolderToggle = useCallback((path: string) => {
    setExpandedFolders(prev => {
      const next = new Set(prev)
      if (next.has(path)) {
        next.delete(path)
      } else {
        next.add(path)
      }
      return next
    })
  }, [])
  
  // Handle content change
  const handleContentChange = useCallback((value: string | undefined) => {
    if (value !== undefined) {
      setFileContent(value)
      setIsModified(true)
    }
  }, [])
  
  // Handle save
  const handleSave = useCallback(async () => {
    if (!editorState?.activeTab || !isModified) return
    
    setIsSaving(true)
    try {
      await updateNote(editorState.activeTab, fileContent)
      setIsModified(false)
    } finally {
      setIsSaving(false)
    }
  }, [editorState?.activeTab, fileContent, isModified, updateNote])
  
  // Keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 's') {
        e.preventDefault()
        handleSave()
      }
      if ((e.metaKey || e.ctrlKey) && e.key === 'n') {
        e.preventDefault()
        setShowNewNote(true)
      }
    }
    
    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [handleSave])
  
  // Handle create note
  const handleCreateNote = useCallback(async (path: string) => {
    await createNote(path, '')
    await refresh()
    await openTab(path)
  }, [createNote, refresh, openTab])
  
  // Handle delete note
  const handleDeleteNote = useCallback(async (path: string) => {
    await deleteNote(path)
    closeTab(path)
    await refresh()
  }, [deleteNote, closeTab, refresh])
  
  // Handle reset workspace (clears all state)
  const handleResetWorkspace = useCallback(async () => {
    if (!window.confirm('Reset workspace? This will clear all notes and tabs.')) {
      return
    }
    
    try {
      // Clear all notes from IndexedDB
      for (const note of notes) {
        await deleteNote(note.path)
      }
      
      // Clear all tabs
      clearAllTabs()
      
      // Clear streaming content
      setStreamingContent(null)
      
      // Clear file content
      setFileContent('')
      setIsModified(false)
      
      // Refresh notes list
      await refresh()
      
      console.log('[NotesMode] Workspace reset complete')
    } catch (err) {
      console.error('[NotesMode] Failed to reset workspace:', err)
    }
  }, [notes, deleteNote, clearAllTabs, setStreamingContent, refresh])
  
  // Handle editor mount
  const handleEditorMount: OnMount = (editor) => {
    editorRef.current = editor
  }
  
  // Check if current file supports preview
  const currentFileSupportsPreview = editorState?.activeTab ? supportsPreview(editorState.activeTab) : false
  const currentFileType = editorState?.activeTab ? getFileType(editorState.activeTab) : null
  
  // Auto-enable preview for mermaid files when tab changes
  useEffect(() => {
    if (editorState?.activeTab?.endsWith('.mmd')) {
      setShowPreview(true)
    }
  }, [editorState?.activeTab])
  
  // Auto-scroll editor to end while streaming
  useEffect(() => {
    if (streamingContent?.isStreaming && editorRef.current) {
      const model = editorRef.current.getModel()
      if (model) {
        const lineCount = model.getLineCount()
        editorRef.current.revealLine(lineCount)
        // Also position cursor at the end
        editorRef.current.setPosition({ lineNumber: lineCount, column: 1 })
      }
    }
  }, [streamingContent?.content, streamingContent?.isStreaming])
  
  // Loading state
  if (workspaceLoading || notesLoading) {
    return (
      <div className="flex items-center justify-center h-full sandbox-bg">
        <Spinner className="h-6 w-6 animate-spin sandbox-text-muted" />
      </div>
    )
  }
  
  return (
    <div className="flex flex-col h-full sandbox-bg">
      {/* Header */}
      <div className="flex items-center justify-between px-3 py-1.5 sandbox-header">
        <div className="flex items-center gap-2">
          <span className="text-xs sandbox-text-secondary">{workspace?.name || 'Notes'}</span>
          {isModified && (
            <span className="text-[11px] sandbox-text-warning font-medium">● Unsaved</span>
          )}
        </div>
        
        <div className="flex items-center gap-1.5">
          {/* Preview toggle for md/mermaid */}
          {currentFileSupportsPreview && (
            <Button
              variant="ghost"
              size="sm"
              onClick={() => setShowPreview(!showPreview)}
              className={cn(
                "h-7 px-2 sandbox-btn",
                showPreview ? "sandbox-btn-active" : ""
              )}
            >
              {showPreview ? <Code className="h-3.5 w-3.5 mr-1" /> : <Eye className="h-3.5 w-3.5 mr-1" />}
              <span className="text-xs">{showPreview ? 'Code' : 'Preview'}</span>
            </Button>
          )}
          
          <Button
            variant="ghost"
            size="sm"
            onClick={() => setShowNewNote(true)}
            className="sandbox-btn h-7 px-2"
          >
            <Plus className="h-3.5 w-3.5 mr-1" />
            <span className="text-xs">New</span>
          </Button>
          
          <Button
            variant="ghost"
            size="sm"
            onClick={handleSave}
            disabled={!isModified || isSaving}
            className="sandbox-btn h-7 px-2 disabled:opacity-40"
          >
            <FloppyDisk className="h-3.5 w-3.5 mr-1" />
            <span className="text-xs">Save</span>
          </Button>
          
          {/* Reset button - only show when there are notes or tabs */}
          {(notes.length > 0 || (editorState?.openTabs?.length ?? 0) > 0) && (
            <Tooltip>
              <TooltipTrigger asChild>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={handleResetWorkspace}
                  className="sandbox-btn-danger h-7 w-7 p-0"
                >
                  <ArrowClockwise className="h-3.5 w-3.5" />
                </Button>
              </TooltipTrigger>
              <TooltipContent side="bottom">Reset workspace</TooltipContent>
            </Tooltip>
          )}
        </div>
      </div>
      
      {/* Main content */}
      <div className="flex flex-1 overflow-hidden">
        {/* Sidebar */}
        <div className="w-52 flex-shrink-0 border-r border-[#3c3c3c] flex flex-col bg-[#181818]">
          <div className="px-2.5 py-1.5 border-b border-[#3c3c3c] bg-[#252526]">
            <span className="text-[11px] font-medium uppercase tracking-wider text-zinc-400">Notes</span>
          </div>
          
          <div className="flex-1 overflow-y-auto">
            {notes.length === 0 ? (
              <div className="px-3 py-4 text-xs text-zinc-500 text-center">
                <p className="mb-2">No notes yet</p>
                <Button
                  variant="link"
                  size="sm"
                  className="text-xs text-blue-400 hover:text-blue-300"
                  onClick={() => setShowNewNote(true)}
                >
                  Create your first note
                </Button>
              </div>
            ) : (
              fileTree.map(node => (
                <FileTreeItem
                  key={node.path}
                  node={node}
                  depth={0}
                  activeFile={editorState?.activeTab || null}
                  expandedFolders={expandedFolders}
                  onFileClick={(path) => {
                    openTab(path)
                    setActiveFilePath(path) // Update URL
                  }}
                  onFolderToggle={handleFolderToggle}
                  onDelete={handleDeleteNote}
                />
              ))
            )}
          </div>
        </div>
        
        {/* Editor area */}
        <div className="flex-1 flex flex-col overflow-hidden bg-[#1e1e1e]">
          <EditorTabs
            tabs={editorState?.openTabs || []}
            activeTab={editorState?.activeTab || null}
            onTabClick={(path) => {
              setActiveTab(path)
              setActiveFilePath(path) // Update URL
            }}
            onTabClose={closeTab}
          />
          
          <div className="flex-1 overflow-hidden relative">
            {isLoadingContent && !streamingContent?.isStreaming && (
              <div className="absolute inset-0 bg-[#1e1e1e] z-10 flex items-center justify-center">
                <div className="flex items-center gap-2 text-zinc-400">
                  <Spinner className="h-5 w-5 animate-spin" />
                  <span className="text-sm">Loading content...</span>
                </div>
              </div>
            )}
            {streamingContent?.isStreaming && streamingContent.path === editorState?.activeTab && (
              <div className="absolute top-2 right-2 z-10 flex items-center gap-2 px-2 py-1 rounded bg-blue-600/80 text-white text-xs">
                <Spinner className="h-3 w-3 animate-spin" />
                <span>AI writing...</span>
              </div>
            )}
            {editorState?.activeTab ? (
              showPreview && currentFileType === 'mermaid' ? (
                <MermaidPreview code={streamingContent?.isStreaming && streamingContent.path === editorState.activeTab ? streamingContent.content : fileContent} />
              ) : (
                <Editor
                  height="100%"
                  language={getMonacoLanguage(editorState.activeTab)}
                  value={streamingContent?.isStreaming && streamingContent.path === editorState.activeTab ? streamingContent.content : fileContent}
                  onChange={handleContentChange}
                  onMount={handleEditorMount}
                  options={{
                    minimap: { enabled: false },
                    fontSize: 13,
                    fontFamily: "'JetBrains Mono', 'Fira Code', monospace",
                    lineNumbers: 'on',
                    scrollBeyondLastLine: false,
                    wordWrap: 'on',
                    tabSize: 2,
                    automaticLayout: true,
                    padding: { top: 8, bottom: 8 },
                    renderWhitespace: 'selection',
                    bracketPairColorization: { enabled: true },
                    cursorBlinking: 'smooth',
                    smoothScrolling: true,
                    lineHeight: 20,
                    readOnly: streamingContent?.isStreaming && streamingContent.path === editorState.activeTab, // Read-only while streaming
                  }}
                  theme="vs-dark"
                />
              )
            ) : (
              <div className="flex items-center justify-center h-full">
                <div className="text-center">
                  <div className="w-16 h-16 mx-auto mb-4 rounded-lg bg-[#2d2d2d] flex items-center justify-center">
                    <File className="h-8 w-8 text-zinc-600" />
                  </div>
                  <p className="text-sm text-zinc-500 mb-1">No file open</p>
                  <p className="text-xs text-zinc-600">Create a note or select one from the sidebar</p>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
      
      {/* Status bar */}
      <div className="flex items-center justify-between h-[22px] px-2.5 border-t border-[#3c3c3c] bg-[#007acc] text-white text-[11px]">
        <div className="flex items-center gap-3">
          {editorState?.activeTab && (
            <span className="opacity-90">{getFileType(editorState.activeTab)}</span>
          )}
        </div>
        <div className="flex items-center gap-3">
          <span className="opacity-70">{notes.length} note{notes.length !== 1 ? 's' : ''}</span>
        </div>
      </div>
      
      {/* New note dialog */}
      <NewNoteDialog
        open={showNewNote}
        onOpenChange={setShowNewNote}
        onCreateNote={handleCreateNote}
      />
    </div>
  )
}
