import React from 'react'
import Link from 'next/link'

interface RenderState {
  currentList: Array<{ key: string; line: string }>
  inCodeBlock: boolean
  codeBlockContent: string[]
  keyCounts: Map<string, number>
}

export function renderMarkdown(markdown: string): React.ReactElement[] {
  const lines = markdown.split('\n')
  const elements: React.ReactElement[] = []
  const state: RenderState = {
    currentList: [],
    inCodeBlock: false,
    codeBlockContent: [],
    keyCounts: new Map<string, number>(),
  }

  lines.forEach((line, index) => {
    processLine(line, index, state, elements)
  })

  closeListIfNeeded('', lines.length, state, elements)

  return elements
}

function processLine(line: string, index: number, state: RenderState, elements: React.ReactElement[]): void {
  if (line.startsWith('```')) {
    handleCodeBlock(line, index, state, elements)
    return
  }

  if (state.inCodeBlock) {
    state.codeBlockContent.push(line)
    return
  }

  closeListIfNeeded(line, index, state, elements)

  if (renderHeading(line, index, state, elements)) {
    return
  }
  if (renderListLine(line, index, state)) {
    return
  }
  if (renderLinkLine(line, index, state, elements)) {
    return
  }
  if (renderBoldAndCodeLine(line, index, state, elements)) {
    return
  }
  renderParagraphOrBreak(line, index, state, elements)
}

function renderHeading(line: string, index: number, state: RenderState, elements: React.ReactElement[]): boolean {
  if (line.startsWith('# ')) {
    elements.push(<h1 key={nextElementKey(state, 'h1', line)} className="text-3xl font-bold mt-8 mb-4 text-neon-cyan font-mono">{line.substring(2)}</h1>)
    return true
  }
  if (line.startsWith('## ')) {
    elements.push(<h2 key={nextElementKey(state, 'h2', line)} className="text-2xl font-bold mt-6 mb-3 text-neon-cyan font-mono">{line.substring(3)}</h2>)
    return true
  }
  if (line.startsWith('### ')) {
    elements.push(<h3 key={nextElementKey(state, 'h3', line)} className="text-xl font-semibold mt-4 mb-2 text-neon-cyan font-mono">{line.substring(4)}</h3>)
    return true
  }
  if (line.startsWith('#### ')) {
    elements.push(<h4 key={nextElementKey(state, 'h4', line)} className="text-lg font-semibold mt-3 mb-2 text-neon-cyan font-mono">{line.substring(5)}</h4>)
    return true
  }
  return false
}

function renderListLine(line: string, index: number, state: RenderState): boolean {
  if (line.startsWith('- ') || line.startsWith('* ')) {
    state.currentList.push({ key: nextElementKey(state, 'li', line), line })
    return true
  }
  return false
}

function renderLinkLine(line: string, index: number, state: RenderState, elements: React.ReactElement[]): boolean {
  if (line.includes('[') && line.includes('](')) {
    renderLink(line, index, state, elements)
    return true
  }
  return false
}

function renderBoldAndCodeLine(line: string, index: number, state: RenderState, elements: React.ReactElement[]): boolean {
  if (line.includes('**') || line.includes('`')) {
    renderBoldAndCode(line, index, state, elements)
    return true
  }
  return false
}

function renderParagraphOrBreak(line: string, index: number, state: RenderState, elements: React.ReactElement[]): void {
  if (line.trim() !== '') {
    elements.push(<p key={nextElementKey(state, 'p', line)} className="mb-4 text-cyber-accent">{line}</p>)
    return
  }
  if (elements.length > 0) {
    const last = elements[elements.length - 1] as { type?: unknown }
    if (last?.type !== 'br') {
      elements.push(<br key={nextElementKey(state, 'br', 'br')} />)
    }
  }
}

function handleCodeBlock(
  _line: string,
  index: number,
  state: RenderState,
  elements: React.ReactElement[]
): void {
  const nextState = state
  if (state.inCodeBlock) {
    elements.push(
      <pre key={nextElementKey(state, 'code', state.codeBlockContent.join('\n'))} className="bg-cyber-darker border border-neon-cyan/20 p-4 rounded-lg overflow-x-auto my-4 text-neon-cyan font-mono text-sm">
        <code>{state.codeBlockContent.join('\n')}</code>
      </pre>
    )
    nextState.codeBlockContent = []
    nextState.inCodeBlock = false
  } else {
    nextState.inCodeBlock = true
  }
}

function closeListIfNeeded(
  line: string,
  index: number,
  state: RenderState,
  elements: React.ReactElement[]
): void {
  const nextState = state
  if (state.currentList.length > 0 && !line.startsWith('- ') && !line.startsWith('* ') && line.trim() !== '') {
    const keySeed = `${state.currentList[0]?.key ?? ''}-${state.currentList.length}-${index}`
    elements.push(
      <ul key={nextElementKey(state, 'list', keySeed)} className="list-disc list-inside mb-4 space-y-1 text-cyber-accent marker:text-neon-cyan">
        {state.currentList.map((item) => (
          <li key={item.key} className="ml-4">{item.line.substring(2).trim()}</li>
        ))}
      </ul>
    )
    nextState.currentList = []
  }
}

function createLinkElement(
  text: string,
  href: string,
  key: string,
  isExternal: boolean
): React.ReactElement {
  const className = 'text-neon-green hover:text-neon-cyan underline transition-colors'
  if (isExternal) {
    return (
      <a key={key} href={href} target="_blank" rel="noopener noreferrer" className={className}>
        {text}
      </a>
    )
  }
  return (
    <Link key={key} href={href} className={className}>
      {text}
    </Link>
  )
}

function renderLink(line: string, index: number, state: RenderState, elements: React.ReactElement[]): void {
  const linkRegex = /\[([^\]]+)\]\(([^)]+)\)/g
  let lastIndex = 0
  const parts: (string | React.ReactElement)[] = []
  let match

  while ((match = linkRegex.exec(line)) !== null) {
    if (match[2]) {
      if (!match[1] || match.index > lastIndex) {
        parts.push(line.substring(lastIndex, match.index))
      }
      const href = match[2]
      const isExternal = href.startsWith('http')
      if (match[1]) {
        parts.push(createLinkElement(match[1], href, `link-${index}-${match.index}`, isExternal))
      }
      lastIndex = match.index + match[0].length
    }
  }

  if (lastIndex < line.length) {
    parts.push(line.substring(lastIndex))
  }

  elements.push(<p key={nextElementKey(state, 'p', line)} className="mb-4">{parts}</p>)
}

function renderBoldAndCode(line: string, index: number, state: RenderState, elements: React.ReactElement[]): void {
  const parts: (string | React.ReactElement)[] = []
  const codeRegex = /`([^`]+)`/g
  let codeMatch
  let lastIndex = 0

  while ((codeMatch = codeRegex.exec(line)) !== null) {
    if (codeMatch.index > lastIndex) {
      const beforeCode = line.substring(lastIndex, codeMatch.index)
      processBold(beforeCode, parts)
    }
    parts.push(
      <code key={`code-${codeMatch.index}`} className="bg-cyber-darker text-neon-cyan px-1 py-0.5 rounded text-sm font-mono border border-neon-cyan/20">
        {codeMatch[1]}
      </code>
    )
    lastIndex = codeMatch.index + codeMatch[0].length
  }

  if (lastIndex < line.length) {
    const remaining = line.substring(lastIndex)
    processBold(remaining, parts)
  }

  elements.push(<p key={nextElementKey(state, 'p', line)} className="mb-4">{parts.length > 0 ? parts : line}</p>)
}

function processBold(text: string, parts: (string | React.ReactElement)[]): void {
  const boldParts = text.split(/(\*\*[^*]+\*\*)/g)
  const seen = new Map<string, number>()
  boldParts.forEach((part) => {
    if (part.startsWith('**') && part.endsWith('**')) {
      const count = (seen.get(part) ?? 0) + 1
      seen.set(part, count)
      parts.push(<strong key={`bold-${count}-${part}`} className="text-neon-green font-semibold">{part.slice(2, -2)}</strong>)
    } else if (part) {
      parts.push(part)
    }
  })
}

function nextElementKey(state: RenderState, prefix: string, raw: string): string {
  const base = buildKeyBase(prefix, raw)
  const nextCount = (state.keyCounts.get(base) ?? 0) + 1
  state.keyCounts.set(base, nextCount)
  return `${base}-${nextCount}`
}

function buildKeyBase(prefix: string, raw: string): string {
  const normalized = raw.trim().replace(/\s+/g, ' ').slice(0, 80)
  return `${prefix}-${normalized}`
}
