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

type LexNode = {
  type: string
  text?: string
  format?: number
  tag?: string
  listType?: string
  children?: LexNode[]
  fields?: { url?: string; newTab?: boolean }
  url?: string
}

type EditorState = { root: { children: LexNode[] } }

// Text format bitmask: 1=bold 2=italic 4=strikethrough 8=underline 16=code
function applyFormat(text: string, format: number): React.ReactNode {
  let el: React.ReactNode = text
  if (format & 16) el = <code className="bg-[#f0f4f8] text-orange font-mono text-[0.85em] px-1.5 py-0.5 rounded">{el}</code>
  if (format & 1)  el = <strong className="font-bold text-[#1a1f2e]">{el}</strong>
  if (format & 2)  el = <em>{el}</em>
  if (format & 8)  el = <u className="underline underline-offset-2">{el}</u>
  if (format & 4)  el = <s className="line-through opacity-60">{el}</s>
  return el
}

function children(nodes: LexNode[], prefix: string): React.ReactNode[] {
  return nodes.map((n, i) => node(n, `${prefix}.${i}`))
}

function node(n: LexNode, key: string): React.ReactNode {
  switch (n.type) {

    case 'text': {
      const fmt = n.format ?? 0
      return (
        <React.Fragment key={key}>
          {fmt === 0 ? n.text : applyFormat(n.text ?? '', fmt)}
        </React.Fragment>
      )
    }

    case 'linebreak':
      return <br key={key} />

    case 'paragraph':
      if (!n.children?.length) return <div key={key} className="h-3" />
      return <p key={key} className="mb-5 leading-7 text-[#3a4051]">{children(n.children, key)}</p>

    case 'heading': {
      const tag = (n.tag ?? 'h2') as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
      const styles = {
        h1: 'text-3xl font-black text-navy-900 mt-10 mb-4 leading-tight',
        h2: 'text-2xl font-bold text-navy-900 mt-9 mb-3 pb-2.5 border-b border-[#e2e6ed]',
        h3: 'text-xl font-bold text-[#1a1f2e] mt-7 mb-2',
        h4: 'text-lg font-semibold text-[#1a1f2e] mt-6 mb-2',
        h5: 'text-base font-semibold text-[#1a1f2e] mt-5 mb-1',
        h6: 'text-sm font-semibold uppercase tracking-wide text-[#5c6472] mt-4 mb-1',
      }
      return React.createElement(tag, { key, className: styles[tag] }, children(n.children ?? [], key))
    }

    case 'list': {
      const ordered = n.listType === 'number'
      const Tag = ordered ? 'ol' : 'ul'
      const cls = ordered
        ? 'list-decimal list-outside pl-6 mb-5 space-y-2 text-[#3a4051] leading-7'
        : 'list-disc list-outside pl-6 mb-5 space-y-2 text-[#3a4051] leading-7'
      return <Tag key={key} className={cls}>{children(n.children ?? [], key)}</Tag>
    }

    case 'listitem':
      return <li key={key} className="pl-1">{children(n.children ?? [], key)}</li>

    case 'quote':
      return (
        <blockquote key={key} className="border-l-4 border-brand bg-brand/5 pl-5 pr-4 py-3 my-7 rounded-r-2xl italic text-[#3a4051] text-lg leading-7">
          {children(n.children ?? [], key)}
        </blockquote>
      )

    case 'horizontalrule':
      return <hr key={key} className="my-8 border-[#e2e6ed]" />

    case 'code': {
      const text = (n.children ?? []).map(c => c.text ?? '').join('')
      return (
        <pre key={key} className="bg-navy-900 text-[#e2e6ed] font-mono text-sm rounded-2xl px-6 py-5 my-6 overflow-x-auto leading-6">
          <code>{text}</code>
        </pre>
      )
    }

    case 'link':
    case 'autolink': {
      const url = n.fields?.url ?? n.url ?? '#'
      const external = url.startsWith('http')
      const cls = 'text-brand hover:text-brand-dark underline underline-offset-2 transition-colors'
      if (external) {
        return <a key={key} href={url} target="_blank" rel="noopener noreferrer" className={cls}>{children(n.children ?? [], key)}</a>
      }
      return <Link key={key} href={url} className={cls}>{children(n.children ?? [], key)}</Link>
    }

    default:
      if (n.children?.length) return <React.Fragment key={key}>{children(n.children, key)}</React.Fragment>
      return null
  }
}

export default function RichText({ content }: { content: unknown }) {
  if (!content || typeof content !== 'object') return null
  const state = content as EditorState
  if (!state.root?.children) return null
  return (
    <div className="rich-text text-base">
      {state.root.children.map((n, i) => node(n, `r${i}`))}
    </div>
  )
}
