// CodeBlock — pretty wrapper for a `<pre><code>` fragment with an
// optional filename header, language label, and a one-click copy
// button. Three rendering modes, in priority order:
//   1. `html` set     → render pre-highlighted Shiki HTML verbatim.
//                       (The docs app's MDX pipeline pre-renders code
//                       fences at build time and feeds them here.)
//   2. `code` + `language` matching SHIKI_LANGS → lazy-load Shiki and
//                       highlight at runtime via <HighlightedCode>.
//                       Until the WASM lands, the body falls back to
//                       plain escaped code so layout doesn't jump.
//   3. `code` only    → plain <pre><code>, no highlighting.
//
// Browser-only behaviour (copy button) is opt-in: when `interactive:
// 'islands'` strips the rest of the JS, the button stays a static
// <button> that doesn't do anything until JS lands; visually still
// looks right, just non-functional. That's the same compromise the
// rest of the kit makes.
//
// For Fumadocs-style tabs around a CodeBlock, use the `Tabs` primitive
// in this folder.

import { useState, type ReactNode } from 'react'
import { cn } from '../cn'
import { HighlightedCode, SHIKI_LANGS, type ShikiLang } from './highlightedCode'

const SHIKI_LANG_SET = SHIKI_LANGS as ReadonlyArray<string>
const asShikiLang = (s: string | undefined): ShikiLang | null =>
  s && SHIKI_LANG_SET.includes(s) ? (s as ShikiLang) : null

interface CodeBlockProps {
  /** Filename label shown in the header. Optional. */
  readonly filename?: string
  /** Language label shown in the top-right. Optional. */
  readonly language?: string
  /** Pre-highlighted HTML (e.g. from Shiki) — rendered via
   *  dangerouslySetInnerHTML. Pick this OR `code`, not both. */
  readonly html?: string
  /** Plain code text — renders inside a styled <pre><code>. */
  readonly code?: string
  readonly className?: string
  /** Copy-button caption + `aria-label` before a copy. Default `'Copy'` /
   *  `'Copy code'`. */
  readonly copyLabel?: string
  readonly copyAriaLabel?: string
  /** Copy-button caption + `aria-label` after a successful copy. Default
   *  `'Copied'`. */
  readonly copiedLabel?: string
  readonly copiedAriaLabel?: string
}

export const CodeBlock = ({
  filename, language, html, code, className,
  copyLabel = 'Copy', copyAriaLabel = 'Copy code',
  copiedLabel = 'Copied', copiedAriaLabel = 'Copied',
}: CodeBlockProps): ReactNode => {
  const [copied, setCopied] = useState(false)
  // Text used by the copy button: prefer the raw `code`; when only
  // pre-rendered HTML is available, fall back to stripping tags at
  // copy time.
  const copyText = (): string => {
    if (code) return code
    if (html) {
      const tmp = typeof document !== 'undefined' ? document.createElement('div') : null
      if (!tmp) return ''
      tmp.innerHTML = html
      return tmp.textContent ?? ''
    }
    return ''
  }
  const doCopy = (): void => {
    const text = copyText()
    if (!text || typeof navigator === 'undefined' || !navigator.clipboard) return
    navigator.clipboard.writeText(text).then(() => {
      setCopied(true)
      setTimeout(() => setCopied(false), 1400)
    }).catch(() => { /* clipboard denied; ignore */ })
  }

  return (
    <figure className={cn('not-prose my-5 rounded-lg overflow-hidden border border-border bg-[oklch(0.18_0.005_280)]', className)}>
      {(filename || language) ? (
        <header className="flex items-center justify-between border-b border-border/60 px-4 py-2 bg-card/40">
          {filename ? (
            <span className="text-xs text-muted-foreground font-mono">{filename}</span>
          ) : <span />}
          {language ? (
            <span className="text-[0.65rem] uppercase tracking-wider text-muted-foreground/80 font-semibold">
              {language}
            </span>
          ) : null}
        </header>
      ) : null}
      <div className="relative">
        <button
          type="button"
          onClick={doCopy}
          aria-label={copied ? copiedAriaLabel : copyAriaLabel}
          className="absolute top-3 right-3 inline-flex items-center gap-1 rounded-md border border-border/60 bg-background/70 backdrop-blur px-2 py-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
        >
          {copied ? (
            <>
              <svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
                <path d="M3 6.5 L5 8.5 L9 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
              </svg>
              {copiedLabel}
            </>
          ) : (
            <>
              <svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
                <rect x="3" y="3" width="6" height="6" rx="1" stroke="currentColor" strokeWidth="1.5" />
                <path d="M5 3 V2.5 A0.5 0.5 0 0 1 5.5 2 H8.5 A0.5 0.5 0 0 1 9 2.5 V5.5 A0.5 0.5 0 0 1 8.5 6 H8" stroke="currentColor" strokeWidth="1.5" />
              </svg>
              {copyLabel}
            </>
          )}
        </button>
        {html ? (
          <div
            className="text-sm leading-relaxed [&_pre]:!m-0 [&_pre]:!bg-transparent [&_pre]:p-4 overflow-x-auto"
            dangerouslySetInnerHTML={{ __html: html }}
          />
        ) : code && asShikiLang(language) ? (
          <HighlightedCode
            code={code}
            lang={asShikiLang(language)!}
            className="[&_pre]:!p-4 [&_pre]:!m-0 [&_pre]:!bg-transparent"
          />
        ) : (
          <pre className="p-4 text-sm leading-relaxed overflow-x-auto"><code>{code}</code></pre>
        )}
      </div>
    </figure>
  )
}
