/**
 * CodePanel — right side of the code viewer overlay.
 *
 * Uses CodeMirror 6 for viewing, editing, search/replace.
 */

import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import CodeMirror, { type ReactCodeMirrorRef } from '@uiw/react-codemirror';
import { javascript } from '@codemirror/lang-javascript';
import { python } from '@codemirror/lang-python';
import { java } from '@codemirror/lang-java';
import { css } from '@codemirror/lang-css';
import { html } from '@codemirror/lang-html';
import { json } from '@codemirror/lang-json';
import { markdown } from '@codemirror/lang-markdown';
import { rust } from '@codemirror/lang-rust';
import { go } from '@codemirror/lang-go';
import { sql } from '@codemirror/lang-sql';
import { xml } from '@codemirror/lang-xml';
import { yaml } from '@codemirror/lang-yaml';
import { oneDark } from '@codemirror/theme-one-dark';
import { EditorView, Decoration, type DecorationSet, ViewPlugin, type ViewUpdate, keymap } from '@codemirror/view';
import { EditorState } from '@codemirror/state';
import type { Extension } from '@codemirror/state';
import { search, highlightSelectionMatches } from '@codemirror/search';
import { Streamdown } from 'streamdown';
import 'streamdown/styles.css';
import { Loader2, AlertTriangle, FileQuestion, Pencil, Save, Eye, ZoomIn, ZoomOut, Code2, ChevronLeft, ChevronRight } from 'lucide-react';
import { useCodeViewerStore, type FileContent, type BinaryFileInfo } from '@/stores/code-viewer';
import { cn } from '@/lib/utils';
import { authFetch } from '@/lib/auth';
import { streamdownComponents } from '@/features/chat/streamdown-components';
import { useCodePlugin } from '@/lib/streamdown-plugins';
import { CodeNavigator } from './CodeNavigator';
import { t } from '@/locales';

// ── Language extension mapping ────────────────────────────────────

function getLanguageExtension(lang: string) {
  const map: Record<string, () => unknown> = {
    javascript: () => javascript({ jsx: true, typescript: false }),
    typescript: () => javascript({ jsx: true, typescript: true }),
    python: () => python(),
    java: () => java(),
    css: () => css(),
    html: () => html(),
    json: () => json(),
    markdown: () => markdown(),
    rust: () => rust(),
    go: () => go(),
    sql: () => sql(),
    xml: () => xml(),
    yaml: () => yaml(),
    vue: () => javascript({ jsx: true }),
  };
  return map[lang]?.() ?? undefined;
}

// ── Line highlight via ViewPlugin (survives doc re-creation) ──────

const navHighlightDeco = Decoration.line({ class: 'cm-navHighlight' });

const navHighlightPlugin = ViewPlugin.fromClass(class {
  decorations: DecorationSet;
  highlightLine: number | null;
  timer: ReturnType<typeof setTimeout> | null;
  destroyed: boolean;

  constructor() {
    this.decorations = Decoration.none;
    this.highlightLine = null;
    this.timer = null;
    this.destroyed = false;
  }

  setHighlight(line: number | null, view: EditorView) {
    if (this.destroyed) return;
    if (this.timer) { clearTimeout(this.timer); this.timer = null; }
    this.highlightLine = line;
    if (line == null || line < 1 || line > view.state.doc.lines) {
      this.decorations = Decoration.none;
      this.highlightLine = null;
    } else {
      const info = view.state.doc.line(line);
      this.decorations = Decoration.set([navHighlightDeco.range(info.from)]);
    }
    // Clear after 10 seconds
    if (line != null) {
      this.timer = setTimeout(() => {
        if (this.destroyed) return;
        this.highlightLine = null;
        this.decorations = Decoration.none;
        try { view.dispatch({}); } catch { /* view may be destroyed */ }
      }, 10000);
    }
  }

  update(update: ViewUpdate) {
    if (this.destroyed) return;
    // Re-apply decoration if doc changed but we still have a highlight line
    if (update.docChanged && this.highlightLine != null) {
      const line = this.highlightLine;
      if (line < 1 || line > update.state.doc.lines) {
        this.decorations = Decoration.none;
        this.highlightLine = null;
      } else {
        const info = update.state.doc.line(line);
        this.decorations = Decoration.set([navHighlightDeco.range(info.from)]);
      }
    }
  }

  destroy() {
    this.destroyed = true;
    if (this.timer) { clearTimeout(this.timer); this.timer = null; }
  }
}, {
  decorations: (v) => v.decorations,
});

function getHighlightPlugin(view: EditorView) {
  return view.plugin(navHighlightPlugin);
}

const navHighlightTheme = EditorView.baseTheme({
  '.cm-navHighlight': {
    backgroundColor: 'rgba(255, 166, 0, 0.18) !important',
    borderLeft: '2px solid rgba(255, 166, 0, 0.6)',
  },
  '&dark .cm-navHighlight': {
    backgroundColor: 'rgba(255, 166, 0, 0.22) !important',
    borderLeft: '2px solid rgba(255, 166, 0, 0.7)',
  },
});

// ── Ctrl/Cmd+Click to search symbol ──────────────────────────────

const IDENTIFIER_RE = /[\w]+/g;

function findIdentifierAt(text: string, offset: number): string | null {
  IDENTIFIER_RE.lastIndex = 0;
  let m: RegExpExecArray | null;
  while ((m = IDENTIFIER_RE.exec(text)) !== null) {
    if (offset >= m.index && offset <= m.index + m[0].length) {
      return m[0];
    }
  }
  return null;
}

function clickNavExtension() {
  return EditorView.domEventHandlers({
    mouseup(event, view) {
      if (event.ctrlKey || event.metaKey || event.altKey || event.shiftKey || event.button !== 0) return false;
      try {
        const pos = view.posAtCoords(event);
        if (pos == null || pos < 0 || view.state.doc.length === 0 || pos >= view.state.doc.length) return false;

        const state = useCodeViewerStore.getState();
        if (!state.filePath) return false;

        const line = view.state.doc.lineAt(pos);
        const col = pos - line.from;

        const lastLoc = state.navHistory[state.navIndex];
        if (lastLoc && lastLoc.filePath === state.filePath && lastLoc.line === line.number && lastLoc.column === col) {
          return false;
        }

        state.pushNav(state.filePath, line.number, col);
      } catch {
        // Never crash on click recording
      }
      return false;
    },
  });
}

function ctrlClickSearchExtension(workspace: string) {
  return EditorView.domEventHandlers({
    mousedown(event, view) {
      if (!(event.ctrlKey || event.metaKey) || event.button !== 0) return false;
      try {
        const pos = view.posAtCoords(event);
        if (pos == null || pos < 0 || view.state.doc.length === 0 || pos >= view.state.doc.length) return false;

        const line = view.state.doc.lineAt(pos);
        const lineOffset = pos - line.from;
        const symbol = findIdentifierAt(line.text, lineOffset);
        if (!symbol) return false;

        useCodeViewerStore.getState().searchSymbols(symbol);
        getHighlightPlugin(view)?.setHighlight(line.number, view);
      } catch {
        // Never crash on Ctrl+Click search
      }
      return true;
    },
  });
}

// ── CodePanel (top-level) ──────────────────────────────────────────

interface CodePanelProps {
  workspace: string;
}

export function CodePanel({ workspace }: CodePanelProps) {
  const currentFile = useCodeViewerStore((s) => s.currentFile);
  const loading = useCodeViewerStore((s) => s.loading);
  const error = useCodeViewerStore((s) => s.error);
  const lineNumber = useCodeViewerStore((s) => s.lineNumber);

  if (loading && !currentFile) {
    return (
      <div className="h-full flex items-center justify-center">
        <div className="flex flex-col items-center gap-3 text-muted-foreground">
          <Loader2 className="h-8 w-8 animate-spin" />
          <span className="text-[13px]">{t("codeviewer.loading")}</span>
        </div>
      </div>
    );
  }

  if (error) {
    return (
      <div className="h-full flex items-center justify-center">
        <div className="flex flex-col items-center gap-3 text-destructive max-w-md px-4 text-center">
          <AlertTriangle className="h-8 w-8 shrink-0" />
          <span className="text-[13px]">{error}</span>
        </div>
      </div>
    );
  }

  if (!currentFile) {
    return (
      <div className="h-full flex items-center justify-center">
        <div className="flex flex-col items-center gap-3 text-muted-foreground">
          <FileQuestion className="h-8 w-8 shrink-0" />
          <span className="text-[13px]">{t("codeviewer.clickToView")}</span>
        </div>
      </div>
    );
  }

  if ('type' in currentFile && currentFile.type === 'binary') {
    const isImage = currentFile.mimeType.startsWith('image/');
    if (isImage) {
      return <ImagePanel file={currentFile} workspace={workspace} />;
    }
    return <BinaryPanel file={currentFile} />;
  }

  return (
    <CodeContent
      file={currentFile as FileContent}
      highlightLine={lineNumber}
      workspace={workspace}
      isMarkdown={(currentFile as FileContent).language === 'markdown'}
    />
  );
}

// ── BinaryPanel ────────────────────────────────────────────────────

function BinaryPanel({ file }: { file: BinaryFileInfo }) {
  const sizeStr = useMemo(() => {
    const bytes = file.size;
    if (bytes < 1024) return `${bytes} B`;
    if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  }, [file.size]);

  return (
    <div className="h-full flex items-center justify-center">
      <div className="flex flex-col items-center gap-3 text-muted-foreground text-center">
        <FileQuestion className="h-8 w-8 shrink-0" />
        <span className="text-[12px] font-medium">{t("codeviewer.binaryFile")}</span>
        <span className="text-[12px]">
          {file.fileName} ({sizeStr}, {file.mimeType})
        </span>
        <span className="text-[12px] text-muted-foreground/60">
          {t("codeviewer.cannotPreview")}
        </span>
      </div>
    </div>
  );
}

// ── ImagePanel ─────────────────────────────────────────────────────

const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.svg', '.webp']);

function isImageViewable(file: BinaryFileInfo): boolean {
  if (file.mimeType.startsWith('image/')) return true;
  const ext = '.' + (file.fileName.split('.').pop() || '').toLowerCase();
  return IMAGE_EXTENSIONS.has(ext);
}

function ImagePanel({ file, workspace }: { file: BinaryFileInfo; workspace: string }) {
  const [imgUrl, setImgUrl] = useState<string | null>(null);
  const [imgError, setImgError] = useState(false);
  const [zoom, setZoom] = useState(100);
  const [naturalSize, setNaturalSize] = useState({ w: 0, h: 0 });

  useEffect(() => {
    let revoked = false;
    const params = new URLSearchParams({ workspace, file: file.path });
    authFetch(`/api/code/image?${params}`)
      .then((res) => {
        if (!res.ok) throw new Error('Failed to load image');
        return res.blob();
      })
      .then((blob) => {
        if (revoked) return;
        setImgUrl(URL.createObjectURL(blob));
        setImgError(false);
      })
      .catch(() => {
        if (!revoked) setImgError(true);
      });
    return () => {
      revoked = true;
      if (imgUrl) URL.revokeObjectURL(imgUrl);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [workspace, file.path]);

  const handleZoomIn = useCallback(() => setZoom((z) => Math.min(z + 25, 500)), []);
  const handleZoomOut = useCallback(() => setZoom((z) => Math.max(z - 25, 10)), []);
  const handleZoomReset = useCallback(() => setZoom(100), []);

  if (imgError) {
    return <BinaryPanel file={file} />;
  }

  if (!imgUrl) {
    return (
      <div className="h-full flex items-center justify-center">
        <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
      </div>
    );
  }

  const zoomLabel = zoom === 100 ? '1:1' : `${zoom}%`;

  return (
    <div className="h-full flex flex-col min-h-0">
      {/* Image area */}
      <div className="flex-1 min-h-0 overflow-auto flex items-center justify-center p-4 bg-[hsl(var(--muted))]/30">
        {/* eslint-disable-next-line @next/next/no-img-element */}
        <img
          src={imgUrl}
          alt={file.fileName}
          style={{ transform: `scale(${zoom / 100})`, transformOrigin: 'center center' }}
          className="max-w-none transition-transform duration-150"
          onLoad={(e) => {
            const img = e.currentTarget;
            setNaturalSize({ w: img.naturalWidth, h: img.naturalHeight });
          }}
          draggable={false}
        />
      </div>

      {/* Bottom toolbar */}
      <div className="shrink-0 flex items-center justify-center gap-3 px-4 py-1.5 border-t border-[hsl(var(--border))] bg-[hsl(var(--card))]">
        <span className="text-[11px] text-muted-foreground/60 mr-2">
          {file.fileName} {naturalSize.w > 0 && `(${naturalSize.w}×${naturalSize.h})`}
        </span>
        <button
          onClick={handleZoomOut}
          disabled={zoom <= 10}
          className="p-1 rounded hover:bg-[hsl(var(--muted))] transition-colors disabled:opacity-30"
          title={t("codeviewer.zoomOut")}
        >
          <ZoomOut className="w-4 h-4 text-muted-foreground" />
        </button>
        <button
          onClick={handleZoomReset}
          className="px-2 py-0.5 text-[11px] text-muted-foreground rounded hover:bg-[hsl(var(--muted))] transition-colors min-w-[40px] text-center"
          title={t("codeviewer.zoomOriginal")}
        >
          {zoomLabel}
        </button>
        <button
          onClick={handleZoomIn}
          disabled={zoom >= 500}
          className="p-1 rounded hover:bg-[hsl(var(--muted))] transition-colors disabled:opacity-30"
          title={t("codeviewer.zoomIn")}
        >
          <ZoomIn className="w-4 h-4 text-muted-foreground" />
        </button>
      </div>
    </div>
  );
}

// ── MarkdownPreview ─────────────────────────────────────────────────

const FRONTMATTER_RE = /^(---)\r?\n([\s\S]*?)\r?\n\1\r?\n/;

function MarkdownPreview({ content }: { content: string }) {
  const codePlugin = useCodePlugin();
  const match = content.match(FRONTMATTER_RE);
  const frontmatter = match ? match[2] : null;
  const body = match ? content.slice(match[0].length) : content;

  return (
    <div className="px-6 py-4 prose prose-sm dark:prose-invert max-w-none break-words text-foreground">
      {frontmatter && (
        <pre className="not-prose text-[12px] leading-relaxed bg-[hsl(var(--muted))] rounded-md px-3 py-2 mb-4 overflow-x-auto font-mono text-muted-foreground border border-[hsl(var(--border))]">
          {frontmatter}
        </pre>
      )}
      <Streamdown
        mode="static"
        components={streamdownComponents}
        controls={{ code: true, table: true }}
        plugins={codePlugin ? { code: codePlugin } : undefined}
      >
        {body}
      </Streamdown>
    </div>
  );
}

// ── CodeContent ────────────────────────────────────────────────────

interface CodeContentProps {
  file: FileContent;
  highlightLine: number | null;
  workspace: string;
  isMarkdown: boolean;
}

function CodeContent({ file, highlightLine, workspace, isMarkdown }: CodeContentProps) {
  const editable = useCodeViewerStore((s) => s.editable);
  const dirty = useCodeViewerStore((s) => s.dirty);
  const saving = useCodeViewerStore((s) => s.saving);
  const setEditable = useCodeViewerStore((s) => s.setEditable);
  const markDirty = useCodeViewerStore((s) => s.markDirty);
  const saveFile = useCodeViewerStore((s) => s.saveFile);
  const navIndex = useCodeViewerStore((s) => s.navIndex);
  const navHistoryLen = useCodeViewerStore((s) => s.navHistory.length);
  const goBack = useCodeViewerStore((s) => s.goBack);
  const goForward = useCodeViewerStore((s) => s.goForward);

  const cmRef = useRef<ReactCodeMirrorRef>(null);
  const [isDark, setIsDark] = useState(() => document.documentElement.classList.contains('dark'));

  // Markdown-specific state
  const [showSource, setShowSource] = useState(false);
  const [renderedContent, setRenderedContent] = useState(file.content);
  const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const filePath = file.path;
  const language = file.language;

  // Listen for dark mode changes
  useEffect(() => {
    const observer = new MutationObserver(() => {
      setIsDark(document.documentElement.classList.contains('dark'));
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class'],
    });
    return () => observer.disconnect();
  }, []);

  // Markdown: debounce re-render on content change
  const updateMarkdownRender = useCallback((content: string) => {
    if (debounceRef.current) clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => {
      setRenderedContent(content);
    }, 1000);
  }, []);

  // Clean debounce timer on unmount
  useEffect(() => {
    return () => {
      if (debounceRef.current) clearTimeout(debounceRef.current);
    };
  }, []);

  // Sync rendered content when file changes (not from editing)
  useEffect(() => {
    if (!editable) {
      setRenderedContent(file.content);
    }
  }, [file.content, editable]);

  // Reset showSource when file changes
  useEffect(() => {
    setShowSource(false);
  }, [filePath]);

  // Scroll to highlight line — use a ViewUpdate listener instead of raw dispatch
  // so we only operate after CodeMirror has fully updated its document.
  const pendingHighlightRef = useRef<number | null>(null);

  // Sync pending highlight from props to ref
  useEffect(() => {
    if (!highlightLine) return;
    pendingHighlightRef.current = highlightLine;
    // Force a no-op dispatch so the updateListener fires even when doc hasn't changed
    requestAnimationFrame(() => {
      try {
        cmRef.current?.view?.dispatch({});
      } catch { /* */ }
    });
  }, [highlightLine, filePath]);

  // ViewUpdate extension: fires after every CodeMirror state change (doc update, etc.)
  const highlightUpdateHandler = useMemo(() => {
    return EditorView.updateListener.of((update) => {
      const line = pendingHighlightRef.current;
      if (line == null || line <= 0) return;
      pendingHighlightRef.current = null;
      const view = update.view;
      if (view.state.doc.length === 0 || line > view.state.doc.lines) return;
      try {
        const pos = view.state.doc.line(line).from;
        getHighlightPlugin(view)?.setHighlight(line, view);
        view.dispatch({ effects: [EditorView.scrollIntoView(pos, { y: 'center' })] });
      } catch { /* Never crash */ }
    });
  }, []);

  // Ctrl+S to save
  useEffect(() => {
    const handleKey = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === 's') {
        e.preventDefault();
        if (editable && dirty) saveFile();
      }
    };
    window.addEventListener('keydown', handleKey);
    return () => window.removeEventListener('keydown', handleKey);
  }, [editable, dirty, saveFile]);

  // Build extensions
  const extensions = useMemo(() => {
    const monoFont = '"JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace';
    const exts: Extension[] = [
      EditorView.theme({
        '&': { fontSize: '13px' },
        '.cm-content': { fontFamily: monoFont },
        '.cm-gutters': { fontFamily: monoFont },
      }),
      EditorState.phrases.of({
        'Find': t('codeviewer.find'),
        'Replace': t('codeviewer.replace'),
        'next': t('codeviewer.next'),
        'previous': t('codeviewer.previous'),
        'all': t('codeviewer.all'),
        'match case': t('codeviewer.matchCase'),
        'regexp': t('codeviewer.regexp'),
        'by word': t('codeviewer.byWord'),
        'replace': t('codeviewer.replace'),
        'replace all': t('codeviewer.replaceAll'),
        'close': t('codeviewer.close'),
        'current match': t('codeviewer.currentMatch'),
        'on line': t('codeviewer.onLine'),
        'replaced match on line $': t('codeviewer.replacedOnLine'),
        'replaced $ matches': t('codeviewer.replacedMatches'),
        'Go to line': t('codeviewer.goToLine'),
        'go': t('codeviewer.go'),
      }),
      search({ top: true }),
      highlightSelectionMatches(),
      navHighlightPlugin,
      EditorView.lineWrapping,
      navHighlightTheme,
      highlightUpdateHandler,
      EditorState.readOnly.of(!editable),
      keymap.of([
        {
          key: 'Mod-s',
          run: () => {
            if (editable && dirty) saveFile();
            return true;
          },
        },
      ]),
    ];

    const langExt = getLanguageExtension(language);
    if (langExt) exts.push(langExt as Extension);

    // Ctrl/Cmd+Click to search symbol
    exts.push(ctrlClickSearchExtension(workspace));

    // Plain click to record navigation position
    exts.push(clickNavExtension());

    return exts;
  }, [language, editable, dirty, saveFile, workspace]);

  const handleChange = useCallback((value: string) => {
    const currentFile = useCodeViewerStore.getState().currentFile;
    if (currentFile && 'content' in currentFile) {
      useCodeViewerStore.setState({
        currentFile: { ...currentFile, content: value },
      });
      markDirty();
    }
    // Markdown: debounce re-render
    if (isMarkdown) {
      updateMarkdownRender(value);
    }
  }, [markDirty, isMarkdown, updateMarkdownRender]);

  const handleToggleEdit = useCallback(() => {
    setEditable(!editable);
  }, [editable, setEditable]);

  // Determine what to show in the body area
  const isMarkdownRenderMode = isMarkdown && !showSource && !editable;
  const isMarkdownEditMode = isMarkdown && !showSource && editable;
  const showCodeEditor = !isMarkdown || showSource || editable;

  return (
    <div className="flex flex-col h-full min-h-0 relative">
      {/* File header with edit toggle */}
      <FileHeader
        filePath={filePath}
        language={language}
        lineCount={file.totalLines}
        truncated={file.truncated}
        editable={editable}
        dirty={dirty}
        saving={saving}
        onToggleEdit={handleToggleEdit}
        onSave={saveFile}
        isMarkdown={isMarkdown}
        showSource={showSource}
        onToggleSource={() => setShowSource(!showSource)}
        navIndex={navIndex}
        navHistoryLen={navHistoryLen}
        goBack={goBack}
        goForward={goForward}
      />

      {/* Body area */}
      {isMarkdownEditMode ? (
        // Markdown edit mode: left editor + right preview
        <div className="flex-1 min-h-0 flex">
          {/* Editor pane */}
          <div className="w-1/2 min-h-0 overflow-hidden border-r border-[hsl(var(--border))]">
            <CodeMirror
              ref={cmRef}
              value={file.content}
              height="100%"
              theme={isDark ? oneDark : undefined}
              extensions={extensions}
              onChange={handleChange}
              className="h-full text-[13px]"
              basicSetup={{
                lineNumbers: true,
                highlightActiveLine: true,
                bracketMatching: true,
                closeBrackets: editable,
                indentOnInput: editable,
                foldGutter: true,
                searchKeymap: true,
              }}
            />
          </div>
          {/* Preview pane */}
          <div className="w-1/2 min-h-0 overflow-auto">
            <MarkdownPreview content={renderedContent} />
          </div>
        </div>
      ) : isMarkdownRenderMode ? (
        // Markdown read mode: full render
        <div className="flex-1 min-h-0 overflow-auto">
          <MarkdownPreview content={file.content} />
        </div>
      ) : (
        // Source code mode (or non-markdown)
        <div className="flex-1 min-h-0 overflow-hidden">
          <CodeMirror
            ref={cmRef}
            value={file.content}
            height="100%"
            theme={isDark ? oneDark : undefined}
            extensions={extensions}
            onChange={handleChange}
            className="h-full text-[13px]"
            basicSetup={{
              lineNumbers: true,
              highlightActiveLine: true,
              bracketMatching: true,
              closeBrackets: editable,
              indentOnInput: editable,
              foldGutter: true,
              searchKeymap: true,
            }}
          />
        </div>
      )}

      {/* Navigator overlay */}
      <CodeNavigator workspace={workspace} currentFilePath={filePath} />
    </div>
  );
}

// ── FileHeader ─────────────────────────────────────────────────────

interface FileHeaderProps {
  filePath: string;
  language: string;
  lineCount: number;
  truncated: boolean;
  editable: boolean;
  dirty: boolean;
  saving: boolean;
  onToggleEdit: () => void;
  onSave: () => void;
  isMarkdown?: boolean;
  showSource?: boolean;
  onToggleSource?: () => void;
  navIndex: number;
  navHistoryLen: number;
  goBack: () => void;
  goForward: () => void;
}

const FileHeader = memo(function FileHeader({
  filePath,
  language,
  lineCount,
  truncated,
  editable,
  dirty,
  saving,
  onToggleEdit,
  onSave,
  isMarkdown,
  showSource,
  onToggleSource,
  navIndex,
  navHistoryLen,
  goBack,
  goForward,
}: FileHeaderProps) {
  return (
    <div className="border-b border-[hsl(var(--border))] shrink-0 bg-[hsl(var(--card))]">
      <div className="flex items-center gap-2 px-4 py-2">
        <span className="text-[13px] text-[hsl(var(--foreground))] font-medium truncate flex-1 min-w-0">
          {filePath}
        </span>
      <span className="text-[11px] text-muted-foreground/60 shrink-0">
        {language}
      </span>
      <span className="text-[11px] text-muted-foreground/60 shrink-0">
        {lineCount} {t("codeviewer.lines").replace("${count}", String(lineCount))}
      </span>
      {truncated && (
        <span className="text-[11px] text-amber-500 shrink-0">
          {t("codeviewer.truncated")}
        </span>
      )}

      {/* Show source toggle (markdown only) */}
      {isMarkdown && onToggleSource && (
        <button
          onClick={onToggleSource}
          className={cn(
            'flex items-center gap-1 px-2 py-1 text-[12px] rounded border transition-colors shrink-0',
            showSource
              ? 'border-purple-400 bg-purple-500/10 text-purple-500'
              : 'border-[hsl(var(--border))] hover:bg-[hsl(var(--muted))] text-muted-foreground',
          )}
          title={showSource ? t('codeviewer.showRendered') : t('codeviewer.showSource')}
        >
          <Code2 className="h-3 w-3" />
          {t("codeviewer.source")}
        </button>
      )}

      {/* Edit/Save controls */}
      <div className="flex items-center gap-1 shrink-0 ml-2">
        <button
          onClick={onToggleEdit}
          className={cn(
            'flex items-center gap-1 px-2 py-1 text-[12px] rounded border transition-colors',
            editable
              ? 'border-blue-400 bg-blue-500/10 text-blue-500'
              : 'border-[hsl(var(--border))] hover:bg-[hsl(var(--muted))] text-muted-foreground',
          )}
          title={editable ? t('codeviewer.toggleReadonly') : t('codeviewer.toggleEdit')}
        >
          {editable ? <Eye className="h-3 w-3" /> : <Pencil className="h-3 w-3" />}
          {editable ? t('codeviewer.readonly') : t('codeviewer.edit')}
        </button>
        {editable && dirty && (
          <button
            onClick={onSave}
            disabled={saving}
            className="flex items-center gap-1 px-2 py-1 text-[12px] rounded border border-green-400 bg-green-500/10 text-green-500 hover:bg-green-500/20 disabled:opacity-50 transition-colors"
            title={t("codeviewer.saveTitle")}
          >
            {saving ? <Loader2 className="h-3 w-3 animate-spin" /> : <Save className="h-3 w-3" />}
            {saving ? t('codeviewer.saving') : t('codeviewer.save')}
          </button>
        )}
        {editable && dirty && (
          <span className="text-[11px] text-amber-500 shrink-0">{t("codeviewer.modified")}</span>
        )}
      </div>
    </div>

    {/* Navigation history bar */}
    {navHistoryLen > 1 && (
      <div className="flex items-center gap-1 px-4 py-1 border-t border-[hsl(var(--border))]/50">
        <button
          onClick={goBack}
          className="flex items-center gap-0.5 px-1.5 py-0.5 text-[11px] rounded hover:bg-[hsl(var(--muted))] transition-colors text-muted-foreground"
          title={t('codeviewer.navBack')}
        >
          <ChevronLeft className="h-3 w-3" />
        </button>
        <span className="text-[11px] text-muted-foreground/50">
          {navIndex + 1}/{navHistoryLen}
        </span>
        <button
          onClick={goForward}
          className="flex items-center gap-0.5 px-1.5 py-0.5 text-[11px] rounded hover:bg-[hsl(var(--muted))] transition-colors text-muted-foreground"
          title={t('codeviewer.navForward')}
        >
          <ChevronRight className="h-3 w-3" />
        </button>
      </div>
    )}
  </div>
  );
});
