import { Fragment, type ReactNode } from 'react'

function renderInlineMarkdown(text: string): ReactNode[] {
  const parts = text.split(/(\*\*[^*]+\*\*|`[^`]+`)/g).filter(Boolean)

  return parts.map((part, index) => {
    if (part.startsWith('**') && part.endsWith('**')) {
      return <strong key={index}>{part.slice(2, -2)}</strong>
    }
    if (part.startsWith('`') && part.endsWith('`')) {
      return (
        <code key={index} className="rounded bg-zinc-100 px-1 py-0.5 font-mono text-[0.85em] dark:bg-zinc-800">
          {part.slice(1, -1)}
        </code>
      )
    }
    return <Fragment key={index}>{part}</Fragment>
  })
}

export function renderMarkdownPreview(markdown: string): ReactNode[] {
  const lines = markdown.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n')
  const blocks: ReactNode[] = []
  let paragraph: string[] = []
  let listItems: string[] = []
  let listType: 'bullet' | 'numbered' | null = null

  function flushParagraph() {
    if (paragraph.length === 0) return
    const text = paragraph.join(' ').trim()
    if (text) {
      blocks.push(
        <p key={`p-${blocks.length}`} className="text-sm leading-6 text-zinc-700 dark:text-zinc-300">
          {renderInlineMarkdown(text)}
        </p>,
      )
    }
    paragraph = []
  }

  function flushList() {
    if (!listType || listItems.length === 0) return
    const ListTag = listType === 'numbered' ? 'ol' : 'ul'
    blocks.push(
      <ListTag
        key={`list-${blocks.length}`}
        className={`${listType === 'numbered' ? 'list-decimal' : 'list-disc'} space-y-1 pl-5 text-sm leading-6 text-zinc-700 dark:text-zinc-300`}
      >
        {listItems.map((item, index) => (
          <li key={index}>{renderInlineMarkdown(item)}</li>
        ))}
      </ListTag>,
    )
    listItems = []
    listType = null
  }

  for (const rawLine of lines) {
    const line = rawLine.trim()
    if (!line) {
      flushParagraph()
      flushList()
      continue
    }

    const heading = line.match(/^(#{1,3})\s+(.+)$/)
    if (heading) {
      flushParagraph()
      flushList()
      const level = heading[1].length
      const className =
        level === 1
          ? 'text-lg font-semibold text-zinc-950 dark:text-white'
          : level === 2
            ? 'text-base font-semibold text-zinc-950 dark:text-white'
            : 'text-sm font-semibold text-zinc-950 dark:text-white'
      const HeadingTag = (`h${Math.min(level + 1, 4)}`) as 'h2' | 'h3' | 'h4'
      blocks.push(
        <HeadingTag key={`h-${blocks.length}`} className={className}>
          {renderInlineMarkdown(heading[2])}
        </HeadingTag>,
      )
      continue
    }

    const bullet = line.match(/^[-*]\s+(.+)$/)
    if (bullet) {
      flushParagraph()
      if (listType !== 'bullet') flushList()
      listType = 'bullet'
      listItems.push(bullet[1])
      continue
    }

    const numbered = line.match(/^\d+\.\s+(.+)$/)
    if (numbered) {
      flushParagraph()
      if (listType !== 'numbered') flushList()
      listType = 'numbered'
      listItems.push(numbered[1])
      continue
    }

    flushList()
    paragraph.push(line)
  }

  flushParagraph()
  flushList()

  return blocks
}
