import React, { memo } from 'react';
import { CopyButton } from '@djangocfg/ui-core/components';
import PrettyCode from '../PrettyCode';

interface CodeBlockProps {
  code: string;
  language: string;
  isUser: boolean;
  isCompact?: boolean;
  /**
   * Code surface palette. Default `'dark'` — syntax highlighting
   * ships its own contrast model and reads washed out on a light
   * surface (GitHub / ChatGPT / VSCode convention). Pass `'light'`
   * to opt a host into a light code surface anyway.
   */
  codeTheme?: 'dark' | 'light';
}

/**
 * Markdown code block. Renders <PrettyCode> directly — its own
 * FloatingToolbar already carries the language tag and Copy action.
 *
 * Earlier versions stacked an extra <CopyButton> here too, which
 * surfaced as two copy buttons on every code fence. The fallback
 * branch below still ships its own button because the plain <pre>
 * has no toolbar of its own.
 *
 * Memoised: re-renders only when `code`, `language`, `isUser` or
 * `isCompact` change. `code` is the main trigger — long code blocks
 * should not re-render when parent chat scrolls.
 */
function CodeBlockRaw({ code, language, codeTheme = 'dark' }: CodeBlockProps) {
  // Chat fences are always rendered in PrettyCode's compact mode:
  // 12px font, tighter padding, line-height 1.4. A fenced block in
  // a chat bubble shouldn't outweigh two paragraphs of body text —
  // the standalone PrettyCode story keeps the larger default for
  // docs/diff viewers.
  //
  // The surface defaults to dark: syntax highlighting ships its own
  // contrast model, so a light code surface in a light-theme bubble
  // renders washed out (GitHub / ChatGPT / VSCode convention). Hosts
  // can opt into a light surface via `codeTheme="light"`.
  return (
    <div className="my-2">
      <PrettyCode
        data={code}
        language={language}
        className="text-xs"
        mode={codeTheme}
        customBg={codeTheme === 'light' ? 'bg-code' : undefined}
        isCompact
        // Disable click-to-scroll-isolation in chat markdown: code
        // fences here are part of an assistant reply, not a docs
        // viewer. Forcing the user to click into a small block to
        // scroll past it interrupts the reading flow. The standalone
        // PrettyCode use cases (docs, diff viewers, long code panes)
        // keep the default `true`.
        scrollIsolation={false}
      />
    </div>
  );
}

export const CodeBlock = memo(CodeBlockRaw);

/** Simple `<pre>` fallback used when CodeBlock throws (lazy module
 *  failure, missing PrettyCode peer, etc).
 *
 *  Memoised: re-renders only when `code`, `language`, `isUser` or
 *  `isCompact` change.
 */
function CodeBlockFallbackRaw({ code, codeTheme = 'dark' }: CodeBlockProps) {
  const isDark = codeTheme === 'dark';
  // On the dark surface the copy button is always light; on a light
  // surface it follows the semantic muted token.
  const copyButtonClass =
    `absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity h-8 w-8 ` +
    (isDark
      ? 'text-white/70 hover:text-white hover:bg-white/15'
      : 'text-muted-foreground hover:text-foreground hover:bg-muted');

  return (
    <div className="relative group my-3">
      <CopyButton
        value={code}
        variant="ghost"
        className={copyButtonClass}
        title="Copy code"
      />
      {isDark ? (
        // Fixed dark surface to match PrettyCode's default.
        <pre
          className="p-3 rounded text-xs font-mono overflow-x-auto border"
          style={{
            backgroundColor: '#0d1117',
            color: '#e5e7eb',
            borderColor: '#1f2937',
          }}
        >
          <code>{code}</code>
        </pre>
      ) : (
        <pre className="p-3 rounded text-xs font-mono overflow-x-auto bg-code text-code-foreground border border-code-border">
          <code>{code}</code>
        </pre>
      )}
    </div>
  );
}

export const CodeBlockFallback = memo(CodeBlockFallbackRaw);
