'use client'

import React, { useEffect, useState, useRef } from 'react'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import type { Components } from 'react-markdown'
import { CodeViewer, SupportedLanguage } from '../playground/code-editor'
import { useNavigation } from '@/lib/api-docs/navigation-context'

// 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)
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="my-4 p-4 border border-red-500/30 bg-red-500/10 rounded-lg">
          <div className="text-red-400 text-sm font-medium mb-2">Mermaid Diagram Error</div>
          <div className="text-red-300 text-xs mb-2">{this.state.error}</div>
          <pre className="text-xs text-muted-foreground overflow-x-auto p-2 bg-muted rounded">
            {this.props.code}
          </pre>
        </div>
      )
    }
    return this.props.children
  }
}

// Mermaid preview component
function MermaidPreviewInner({ code }: { code: string }) {
  const [svg, setSvg] = useState<string>('')
  const [error, setError] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const renderIdRef = useRef(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: {
            background: '#1e1e1e',
            primaryColor: '#3b82f6',
            primaryTextColor: '#ffffff',
            primaryBorderColor: '#60a5fa',
            secondaryColor: '#3b82f6',
            secondaryTextColor: '#ffffff',
            secondaryBorderColor: '#60a5fa',
            tertiaryColor: '#3b82f6',
            tertiaryTextColor: '#ffffff',
            tertiaryBorderColor: '#60a5fa',
            mainBkg: '#3b82f6',
            nodeBkg: '#3b82f6',
            nodeBorder: '#60a5fa',
            nodeTextColor: '#ffffff',
            clusterBkg: '#27272a',
            clusterBorder: '#52525b',
            titleColor: '#ffffff',
            lineColor: '#94a3b8',
            fontFamily: 'system-ui, sans-serif',
            fontSize: '14px',
          },
          flowchart: {
            htmlLabels: true,
            useMaxWidth: true,
          }
        })

        const { svg: renderedSvg } = await mermaid.render(
          `mermaid-md-${currentRenderId}-${Date.now()}`,
          code
        )

        if (currentRenderId === renderIdRef.current) {
          setSvg(renderedSvg)
          setError(null)
        }
      } catch (err: unknown) {
        if (currentRenderId === renderIdRef.current) {
          let errorMessage = 'Failed to render diagram'
          if (err instanceof Error) {
            errorMessage = err.message
            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
          }
          console.error('[MermaidPreview] Render error:', errorMessage)
          setError(errorMessage)
        }
      } finally {
        if (currentRenderId === renderIdRef.current) {
          setLoading(false)
        }
      }
    }

    const debounceTimer = setTimeout(renderDiagram, 300)
    return () => clearTimeout(debounceTimer)
  }, [code])

  if (loading) {
    return (
      <div className="my-4 p-4 bg-muted/30 rounded-lg flex items-center justify-center min-h-[100px]">
        <div className="text-muted-foreground text-sm">Rendering diagram...</div>
      </div>
    )
  }

  if (error) {
    return (
      <div className="my-4 p-4 border border-yellow-500/30 bg-yellow-500/10 rounded-lg">
        <div className="text-yellow-400 text-sm font-medium mb-2">Diagram Syntax Error</div>
        <div className="text-yellow-300 text-xs mb-2">{error}</div>
        <pre className="text-xs text-muted-foreground overflow-x-auto p-2 bg-muted rounded">
          {code}
        </pre>
      </div>
    )
  }

  if (!svg) {
    return null
  }

  return (
    <div
      className="my-4 p-4 bg-zinc-900 rounded-lg overflow-x-auto mermaid"
      dangerouslySetInnerHTML={{ __html: svg }}
    />
  )
}

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

interface MarkdownRendererProps {
  content: string
  className?: string
}



// Map common language identifiers to Monaco supported languages
function getMonacoLanguage(lang: string | undefined): SupportedLanguage {
  if (!lang) return 'plaintext'
  
  const langMap: Record<string, SupportedLanguage> = {
    'js': 'javascript',
    'javascript': 'javascript',
    'ts': 'typescript',
    'typescript': 'typescript',
    'json': 'json',
    'xml': 'xml',
    'html': 'html',
    'htm': 'html',
    'bash': 'shell',
    'shell': 'shell',
    'sh': 'shell',
    'zsh': 'shell',
    'curl': 'shell',
    'text': 'plaintext',
    'plaintext': 'plaintext',
  }
  
  return langMap[lang.toLowerCase()] || 'plaintext'
}

/**
 * Generate a URL-friendly slug from heading text
 */
function generateSlug(text: string): string {
  return text
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
}

/**
 * Extract text content from React children
 */
function getTextContent(children: React.ReactNode): string {
  if (typeof children === 'string') return children
  if (typeof children === 'number') return String(children)
  if (Array.isArray(children)) return children.map(getTextContent).join('')
  if (children && typeof children === 'object' && 'props' in children) {
    const element = children as React.ReactElement<{ children?: React.ReactNode }>
    return getTextContent(element.props.children)
  }
  return ''
}

/**
 * Custom link component that handles internal endpoint links
 */
function MarkdownLink({ href, children }: { href?: string; children: React.ReactNode }) {
  const { navigateToEndpoint } = useNavigation()
  
  // Check if this is an internal endpoint link
  // Formats: #operation/operationId, #/paths/~1endpoint/method
  const isEndpointLink = href?.startsWith('#operation/') || href?.startsWith('#/paths/')
  
  if (isEndpointLink) {
    let operationId = ''
    
    if (href?.startsWith('#operation/')) {
      // Format: #operation/post_carts
      operationId = href.replace('#operation/', '')
    } else if (href?.startsWith('#/paths/')) {
      // Format: #/paths/~1carts/post → extract operation (simplified)
      const parts = href.replace('#/paths/', '').split('/')
      const method = parts[parts.length - 1]
      const path = parts.slice(0, -1).join('/').replace(/~1/g, '/')
      operationId = `${method}_${path.replace(/\//g, '_').replace(/^_/, '')}`
    }
    
    return (
      <button
        onClick={() => navigateToEndpoint(operationId)}
        className="text-primary hover:underline font-medium cursor-pointer bg-transparent border-none p-0 inline"
      >
        {children}
      </button>
    )
  }
  
  // External link - open in new tab
  return (
    <a
      href={href}
      target="_blank"
      rel="noopener noreferrer"
      className="text-primary hover:underline font-medium"
    >
      {children}
    </a>
  )
}

const markdownComponents: Partial<Components> = {
  h1: ({ children }) => {
    const text = getTextContent(children)
    const id = generateSlug(text)
    return (
      <h1 id={id} className="text-2xl font-bold mt-8 mb-4 pb-2 border-b border-border scroll-mt-20">{children}</h1>
    )
  },
  h2: ({ children }) => {
    const text = getTextContent(children)
    const id = generateSlug(text)
    return (
      <h2 id={id} className="text-xl font-semibold mt-6 mb-3 scroll-mt-20">{children}</h2>
    )
  },
  h3: ({ children }) => {
    const text = getTextContent(children)
    const id = generateSlug(text)
    return (
      <h3 id={id} className="text-lg font-semibold mt-5 mb-2 scroll-mt-20">{children}</h3>
    )
  },
  h4: ({ children }) => {
    const text = getTextContent(children)
    const id = generateSlug(text)
    return (
      <h4 id={id} className="text-base font-semibold mt-4 mb-2 scroll-mt-20">{children}</h4>
    )
  },
  h5: ({ children }) => {
    const text = getTextContent(children)
    const id = generateSlug(text)
    return (
      <h5 id={id} className="text-sm font-semibold mt-3 mb-1 scroll-mt-20">{children}</h5>
    )
  },
  h6: ({ children }) => {
    const text = getTextContent(children)
    const id = generateSlug(text)
    return (
      <h6 id={id} className="text-sm font-medium mt-2 mb-1 text-muted-foreground scroll-mt-20">{children}</h6>
    )
  },
  p: ({ children }) => (
    <p className="mb-4 leading-7 text-foreground/90">{children}</p>
  ),
  ul: ({ children }) => (
    <ul className="list-disc pl-6 mb-4 space-y-2">{children}</ul>
  ),
  ol: ({ children }) => (
    <ol className="list-decimal pl-6 mb-4 space-y-2">{children}</ol>
  ),
  li: ({ children }) => (
    <li className="leading-7">{children}</li>
  ),
  code: ({ className, children, ...props }) => {
    const match = /language-(\w+)/.exec(className || '')
    const isCodeBlock = !!match
    const detectedLanguage = match?.[1]?.toLowerCase()
    const codeContent = String(children).replace(/\n$/, '')
    
    // Inline code
    if (!isCodeBlock) {
      return (
        <code
          className="px-1.5 py-0.5 bg-muted rounded text-sm font-mono text-foreground"
          {...props}
        >
          {children}
        </code>
      )
    }
    
    // Mermaid code blocks - render as diagrams
    if (detectedLanguage === 'mermaid') {
      return <MermaidPreview code={codeContent} />
    }
    
    // Code block - use Monaco with dark theme and no line numbers
    const language = getMonacoLanguage(detectedLanguage)
    
    return (
      <div className="my-4 dark-editor">
        <CodeViewer
          value={codeContent}
          language={language}
          height="auto"
          minHeight={Math.min(Math.max(codeContent.split('\n').length * 20 + 24, 60), 400)}
          theme="dark"
          showLineNumbers={false}
        />
      </div>
    )
  },
  pre: ({ children }) => {
    // Pre is handled by code block, just pass through
    return <>{children}</>
  },
  blockquote: ({ children }) => (
    <blockquote className="border-l-4 border-primary/50 pl-4 py-1 my-4 bg-muted/30 rounded-r">
      <div className="text-muted-foreground italic">{children}</div>
    </blockquote>
  ),
  a: ({ href, children }) => (
    <MarkdownLink href={href}>{children}</MarkdownLink>
  ),
  strong: ({ children }) => (
    <strong className="font-bold text-foreground">{children}</strong>
  ),
  em: ({ children }) => (
    <em className="italic">{children}</em>
  ),
  hr: () => (
    <hr className="my-8 border-border" />
  ),
  table: ({ children }) => (
    <div className="my-4 overflow-x-auto">
      <table className="min-w-full border border-border rounded-sm overflow-hidden">
        {children}
      </table>
    </div>
  ),
  thead: ({ children }) => (
    <thead className="bg-muted">{children}</thead>
  ),
  tbody: ({ children }) => (
    <tbody className="divide-y divide-border">{children}</tbody>
  ),
  tr: ({ children }) => (
    <tr className="hover:bg-muted/50">{children}</tr>
  ),
  th: ({ children }) => (
    <th className="px-4 py-2 text-left text-sm font-semibold">{children}</th>
  ),
  td: ({ children }) => (
    <td className="px-4 py-2 text-sm">{children}</td>
  ),
}

export function MarkdownRenderer({ content, className = '' }: MarkdownRendererProps) {
  if (!content) return null

  return (
    <div className={`max-w-none ${className}`}>
      <ReactMarkdown 
        components={markdownComponents}
        remarkPlugins={[remarkGfm]}
      >
        {content}
      </ReactMarkdown>
    </div>
  )
}
