import { useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { useEditorStore } from '../../store/editorStore'
import { detectPassiveVoice } from '../../utils/passiveVoice'
import { detectPastProgressive } from '../../utils/pastProgressive'
import { parseAnnotationsFromAIResponse } from '../../utils/annotationParser'
import { tooltipAnalysisCache } from '../Editor/MarkdownEditor'
import '../FileTree/ContextMenu.css'
import './Toolbar.css'

const BIBLE_PROMPTS = {
  full: `Read the full manuscript and generate comprehensive story bible content as markdown. Include:

## Characters
[Detailed profile for every named character: role, physical description, personality, key relationships, arc]

## World & Setting
[Geography, historical period, Basque Country cultural details, atmosphere, key locations]

## Timeline
[Key events in chronological order with chapter references]

## Themes & Motifs
[Recurring symbols, imagery, thematic concerns]

## Continuity Rules
[Facts that must stay consistent: character details, established plot points, internal logic]

Base everything strictly on what is in the manuscript text.`,

  characters: `Read the full manuscript and write character profiles for the Story Bible. Begin your response with the heading \`## Characters\` followed by a blank line. For each named character include: role, physical description, personality traits, key relationships, and arc. Format each character as a ### subsection.`,

  timeline: `Read the full manuscript and extract all significant events in chronological order for the Story Bible. Begin your response with the heading \`## Timeline\` followed by a blank line. Reference chapters where helpful. Format as a numbered list.`,

  world: `Read the full manuscript and write a World & Setting section for the Story Bible. Begin your response with the heading \`## World & Setting\` followed by a blank line. Cover: the Basque Country geography and atmosphere, the historical period and cultural context, and key locations described in the text.`
}

function countWords(text: string): number {
  return text.trim() === '' ? 0 : text.trim().split(/\s+/).length
}

function formatWordCount(n: number): string {
  if (n >= 1000) return `${(n / 1000).toFixed(1)}k`
  return String(n)
}

interface ParagraphInfo {
  text: string
  sentences: number
  words: number
}

function computeParagraphRhythm(text: string): ParagraphInfo[] {
  const blocks = text.split(/\n+/)
  const result: ParagraphInfo[] = []
  for (const block of blocks) {
    const trimmed = block.trim()
    if (!trimmed || !/\w/.test(trimmed)) continue
    if (/^#{1,6}\s/.test(trimmed) || /^-{3,}$/.test(trimmed) || /^={3,}$/.test(trimmed)) continue
    const words = countWords(trimmed)
    if (words < 3) continue
    const sentences = trimmed
      .split(/[.!?]+/)
      .map(s => s.trim())
      .filter(s => s.length > 0 && /\w/.test(s)).length
    result.push({ text: trimmed, sentences, words })
  }
  return result
}

function sentenceCountColor(n: number): string {
  if (n === 1) return '#5b8dd9'
  if (n === 2) return '#6db8a0'
  if (n === 3) return '#7dc76e'
  if (n === 4) return '#b5c45a'
  if (n === 5) return '#d4a83a'
  if (n === 6) return '#d47830'
  if (n === 7) return '#c45040'
  return '#b03030'
}

interface SentenceStats {
  avg: number
  stdDev: number
  totalSentences: number
  /** bins[i] = count of sentences with (i+1) words; bins[30] = sentences with 31+ words */
  bins: number[]
  outliers: Array<{ text: string; wordCount: number }>
}

function computeSentenceStats(text: string): SentenceStats | null {
  const sentences = text
    .split(/[.!?]+/)
    .map(s => s.trim())
    .filter(s => s.length > 0 && /\w/.test(s))
  if (sentences.length === 0) return null
  const lengths = sentences.map(s => countWords(s))
  const avg = lengths.reduce((a, b) => a + b, 0) / lengths.length
  const variance = lengths.reduce((a, b) => a + (b - avg) ** 2, 0) / lengths.length
  const stdDev = Math.sqrt(variance)
  const bins = new Array(31).fill(0)
  const outliers: Array<{ text: string; wordCount: number }> = []
  for (let i = 0; i < sentences.length; i++) {
    const wc = lengths[i]
    bins[Math.min(wc - 1, 30)]++
    if (wc <= 4 || wc >= 26) outliers.push({ text: sentences[i], wordCount: wc })
  }
  return { avg, stdDev, totalSentences: sentences.length, bins, outliers }
}

export function AnalysisToolbar(): JSX.Element {
  const {
    activeFilePath,
    activeFileContent,
    isDirty,
    analysisMode,
    annotations,
    isAILoading,
    setAnnotations,
    clearAnnotations,
    setAnalysisMode,
    addUserMessage,
    finalizeAssistantMessage,
    setStreamingContent,
    setAILoading,
    setAIError,
    linkAnnotationsToMessage,
    chatHistory,
    projectWordCount,
    setProjectWordCount,
    setRightPanelTab,
    outlineOpen,
    toggleOutline,
    revisionPanelOpen,
    toggleRevisionPanel,
    selectionWordCount
  } = useEditorStore()

  const streamingContentRef = useRef('')
  const streamingRafRef = useRef<number | null>(null)

  const [analyzeOpen, setAnalyzeOpen] = useState(false)
  const analyzeButtonRef = useRef<HTMLButtonElement>(null)
  const analyzeMenuRef = useRef<HTMLDivElement>(null)

  const [statsOpen, setStatsOpen] = useState(false)
  const statsButtonRef = useRef<HTMLButtonElement>(null)
  const statsMenuRef = useRef<HTMLDivElement>(null)

  const [rhythmOpen, setRhythmOpen] = useState(false)
  const rhythmButtonRef = useRef<HTMLButtonElement>(null)
  const rhythmMenuRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    window.api.getProjectWordCount().then(setProjectWordCount).catch(() => {})
  }, [])

  // Refresh project count after a save (isDirty transitions from true → false)
  useEffect(() => {
    if (!isDirty) {
      window.api.getProjectWordCount().then(setProjectWordCount).catch(() => {})
    }
  }, [isDirty])

  // Close dropdowns on file change
  useEffect(() => { setAnalyzeOpen(false); setStatsOpen(false); setRhythmOpen(false) }, [activeFilePath])

  // Click-outside closes dropdown
  useEffect(() => {
    if (!analyzeOpen) return
    const handler = (e: MouseEvent): void => {
      if (
        !analyzeButtonRef.current?.contains(e.target as Node) &&
        !analyzeMenuRef.current?.contains(e.target as Node)
      ) {
        setAnalyzeOpen(false)
      }
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [analyzeOpen])

  // Escape closes dropdowns
  useEffect(() => {
    if (!analyzeOpen && !statsOpen && !rhythmOpen) return
    const handler = (e: KeyboardEvent): void => {
      if (e.key === 'Escape') { setAnalyzeOpen(false); setStatsOpen(false); setRhythmOpen(false) }
    }
    document.addEventListener('keydown', handler)
    return () => document.removeEventListener('keydown', handler)
  }, [analyzeOpen, statsOpen, rhythmOpen])

  // Click-outside closes rhythm popover
  useEffect(() => {
    if (!rhythmOpen) return
    const handler = (e: MouseEvent): void => {
      if (
        !rhythmButtonRef.current?.contains(e.target as Node) &&
        !rhythmMenuRef.current?.contains(e.target as Node)
      ) setRhythmOpen(false)
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [rhythmOpen])

  // Click-outside closes stats popover
  useEffect(() => {
    if (!statsOpen) return
    const handler = (e: MouseEvent): void => {
      if (
        !statsButtonRef.current?.contains(e.target as Node) &&
        !statsMenuRef.current?.contains(e.target as Node)
      ) setStatsOpen(false)
    }
    document.addEventListener('mousedown', handler)
    return () => document.removeEventListener('mousedown', handler)
  }, [statsOpen])

  const hasFile = Boolean(activeFilePath)
  const isStoryBible = activeFilePath?.endsWith('Story Bible.md') ?? false

  const runBibleGeneration = async (prompt: string): Promise<void> => {
    if (!activeFilePath || isAILoading) return
    setAIError(null)
    setRightPanelTab('chat')

    streamingContentRef.current = ''
    addUserMessage(prompt)
    setAILoading(true)

    try {
      await window.api.streamAIMessage(
        {
          mode: 'chat',
          documentContent: activeFileContent,
          documentPath: activeFilePath,
          conversationHistory: chatHistory
            .slice(-10)
            .map((m) => ({ role: m.role, content: m.content })),
          userMessage: prompt
        },
        (chunk: string) => {
          streamingContentRef.current += chunk
          if (streamingRafRef.current === null) {
            streamingRafRef.current = requestAnimationFrame(() => {
              streamingRafRef.current = null
              setStreamingContent(streamingContentRef.current)
            })
          }
        }
      )

      if (streamingRafRef.current !== null) {
        cancelAnimationFrame(streamingRafRef.current)
        streamingRafRef.current = null
      }
      const finalContent = streamingContentRef.current
      streamingContentRef.current = ''
      if (finalContent.length > 0) {
        finalizeAssistantMessage(finalContent, { bibleGeneration: true })
      }
    } catch (err) {
      setAIError(err instanceof Error ? err.message : 'Generation failed')
    } finally {
      setAILoading(false)
    }
  }

  const runPassiveVoice = (): void => {
    if (!hasFile) return
    const found = detectPassiveVoice(activeFileContent)
    const existing = useEditorStore.getState().annotations.filter((a) => a.type !== 'passive_voice')
    setAnnotations([...existing, ...found])
    setAnalysisMode('passive_voice')
  }

  const runPastProgressive = (): void => {
    if (!hasFile) return
    const found = detectPastProgressive(activeFileContent)
    const existing = useEditorStore.getState().annotations.filter((a) => a.type !== 'past_progressive')
    setAnnotations([...existing, ...found])
    setAnalysisMode('past_progressive')
  }

  const runAIAnalysis = async (mode: 'consistency' | 'style' | 'show_tell' | 'critique' | 'weak_verbs' | 'cliches' | 'past_progressive'): Promise<void> => {
    if (!activeFilePath || isAILoading) return

    setAnalysisMode(mode)
    setAIError(null)

    const prompt =
      mode === 'consistency'
        ? 'Please check this chapter for consistency issues (character names, timeline, repeated phrases).'
        : mode === 'style'
          ? 'Please analyze the style and pacing of this chapter and suggest improvements.'
          : mode === 'show_tell'
            ? 'Please identify every passage in this chapter where I am telling rather than showing.'
            : mode === 'weak_verbs'
              ? 'Please identify sentences in this chapter that use weak verbs (was, were, had, got, seemed, appeared, looked, felt) as the main predicate.'
              : mode === 'cliches'
                ? 'Please identify every cliché and overused phrase in this chapter.'
                : mode === 'past_progressive'
                  ? 'Please identify every past progressive construction (was/were + verb-ing) in this chapter that would be stronger in simple past.'
                  : 'Please give me an honest critique of this chapter.'

    streamingContentRef.current = ''
    addUserMessage(prompt)
    setAILoading(true)

    try {
      await window.api.streamAIMessage(
        {
          mode,
          documentContent: activeFileContent,
          documentPath: activeFilePath,
          conversationHistory: chatHistory
            .slice(-10)
            .map((m) => ({ role: m.role, content: m.content })),
          userMessage: prompt
        },
        (chunk: string) => {
          streamingContentRef.current += chunk
          if (streamingRafRef.current === null) {
            streamingRafRef.current = requestAnimationFrame(() => {
              streamingRafRef.current = null
              setStreamingContent(streamingContentRef.current)
            })
          }
        }
      )

      if (streamingRafRef.current !== null) {
        cancelAnimationFrame(streamingRafRef.current)
        streamingRafRef.current = null
      }
      const finalContent = streamingContentRef.current
      streamingContentRef.current = ''

      if (finalContent.length > 0) {
        finalizeAssistantMessage(finalContent)

        // Parse annotations from response
        const overrideType =
          mode === 'show_tell' ? 'show_tell' :
          mode === 'weak_verbs' ? 'weak_verbs' :
          mode === 'cliches' ? 'cliches' :
          mode === 'past_progressive' ? 'past_progressive' :
          undefined
        const { annotations: newAnnotations } = parseAnnotationsFromAIResponse(finalContent, activeFileContent, overrideType)
        if (newAnnotations.length > 0) {
          const currentHistory = useEditorStore.getState().chatHistory
          const lastMsg = currentHistory[currentHistory.length - 1]
          const existing = useEditorStore.getState().annotations.filter((a) => a.type !== mode)
          setAnnotations([...existing, ...newAnnotations])
          if (lastMsg?.role === 'assistant') {
            linkAnnotationsToMessage(lastMsg.id, newAnnotations.map(a => a.id))
          }
        }
      }
    } catch (err) {
      setAIError(err instanceof Error ? err.message : 'Analysis failed')
    } finally {
      setAILoading(false)
    }
  }

  const passiveCount = annotations.filter((a) => a.type === 'passive_voice').length
  const pastProgressiveCount = annotations.filter((a) => a.type === 'past_progressive').length
  const weakVerbsCount = annotations.filter((a) => a.type === 'weak_verbs').length
  const clichesCount = annotations.filter((a) => a.type === 'cliches').length
  const consistencyCount = annotations.filter((a) => a.type === 'consistency').length
  const styleCount = annotations.filter((a) => a.type === 'style').length
  const showTellCount = annotations.filter((a) => a.type === 'show_tell').length
  const critiqueCount = annotations.filter((a) => a.type === 'critique').length
  const totalCount = passiveCount + pastProgressiveCount + weakVerbsCount + clichesCount + consistencyCount + styleCount + showTellCount + critiqueCount
  const anyActive = Boolean(analysisMode)
  const docWordCount = countWords(activeFileContent)
  const sentenceStats = activeFileContent ? computeSentenceStats(activeFileContent) : null
  const avgSentenceLen = sentenceStats ? Math.round(sentenceStats.avg * 10) / 10 : null
  const paragraphRhythm = activeFileContent ? computeParagraphRhythm(activeFileContent) : []
  const maxParaWords = paragraphRhythm.length > 0 ? Math.max(...paragraphRhythm.map(p => p.words)) : 1

  return (
    <div className="toolbar">
      <div className="toolbar-left">
        {isStoryBible ? (
          <>
            <span className="toolbar-bible-label">Generate from manuscript:</span>
            <button
              className="toolbar-btn toolbar-btn-bible"
              onClick={() => runBibleGeneration(BIBLE_PROMPTS.full)}
              disabled={isAILoading}
              title="Generate all story bible sections from the full manuscript"
            >
              {isAILoading ? 'Generating…' : 'Full bible'}
            </button>
            <button
              className="toolbar-btn toolbar-btn-bible"
              onClick={() => runBibleGeneration(BIBLE_PROMPTS.characters)}
              disabled={isAILoading}
              title="Extract character profiles from the manuscript"
            >
              Characters
            </button>
            <button
              className="toolbar-btn toolbar-btn-bible"
              onClick={() => runBibleGeneration(BIBLE_PROMPTS.timeline)}
              disabled={isAILoading}
              title="Extract timeline of events from the manuscript"
            >
              Timeline
            </button>
            <button
              className="toolbar-btn toolbar-btn-bible"
              onClick={() => runBibleGeneration(BIBLE_PROMPTS.world)}
              disabled={isAILoading}
              title="Extract world & setting details from the manuscript"
            >
              World
            </button>
          </>
        ) : (
          <>
            <button
              ref={analyzeButtonRef}
              className={`toolbar-btn toolbar-analyze-btn${anyActive ? ' active' : ''}`}
              onClick={() => setAnalyzeOpen((v) => !v)}
              disabled={!hasFile || isAILoading}
              title="Run analysis on this chapter"
            >
              {isAILoading ? 'Analyzing…' : `Analyze ${analyzeOpen ? '▴' : '▾'}`}
              {totalCount > 0 && !isAILoading && (
                <span className="toolbar-analyze-badge">{totalCount}</span>
              )}
            </button>

            {annotations.length > 0 && (
              <button
                className="toolbar-btn toolbar-btn-clear"
                onClick={() => { clearAnnotations(); tooltipAnalysisCache.clear() }}
                title="Remove all highlights"
              >
                Clear
              </button>
            )}

            {analyzeOpen && analyzeButtonRef.current && createPortal(
              (() => {
                const rect = analyzeButtonRef.current!.getBoundingClientRect()
                return (
                  <div
                    ref={analyzeMenuRef}
                    className="context-menu toolbar-analyze-menu"
                    style={{ top: rect.bottom + 4, left: rect.left }}
                  >
                    <button
                      className={`context-menu-item${analysisMode === 'passive_voice' ? ' active' : ''}`}
                      onClick={() => { setAnalyzeOpen(false); runPassiveVoice() }}
                    >
                      <span>Passive Voice</span>
                      {passiveCount > 0 && <span className="toolbar-analyze-count">{passiveCount}</span>}
                    </button>
                    <button
                      className={`context-menu-item${analysisMode === 'past_progressive' ? ' active' : ''}`}
                      onClick={() => { setAnalyzeOpen(false); runPastProgressive() }}
                    >
                      <span>Past Progressive</span>
                      {pastProgressiveCount > 0 && <span className="toolbar-analyze-count">{pastProgressiveCount}</span>}
                    </button>
                    <button
                      className={`context-menu-item${analysisMode === 'weak_verbs' ? ' active' : ''}`}
                      onClick={() => { setAnalyzeOpen(false); void runAIAnalysis('weak_verbs') }}
                    >
                      <span>Weak Verbs</span>
                      {weakVerbsCount > 0 && <span className="toolbar-analyze-count">{weakVerbsCount}</span>}
                    </button>
                    <button
                      className={`context-menu-item${analysisMode === 'cliches' ? ' active' : ''}`}
                      onClick={() => { setAnalyzeOpen(false); void runAIAnalysis('cliches') }}
                    >
                      <span>Clichés</span>
                      {clichesCount > 0 && <span className="toolbar-analyze-count">{clichesCount}</span>}
                    </button>
                    <button
                      className={`context-menu-item${analysisMode === 'consistency' ? ' active' : ''}`}
                      onClick={() => { setAnalyzeOpen(false); void runAIAnalysis('consistency') }}
                    >
                      <span>Consistency</span>
                      {consistencyCount > 0 && <span className="toolbar-analyze-count">{consistencyCount}</span>}
                    </button>
                    <button
                      className={`context-menu-item${analysisMode === 'style' ? ' active' : ''}`}
                      onClick={() => { setAnalyzeOpen(false); void runAIAnalysis('style') }}
                    >
                      <span>Style</span>
                      {styleCount > 0 && <span className="toolbar-analyze-count">{styleCount}</span>}
                    </button>
                    <button
                      className={`context-menu-item${analysisMode === 'show_tell' ? ' active' : ''}`}
                      onClick={() => { setAnalyzeOpen(false); void runAIAnalysis('show_tell') }}
                    >
                      <span>Show vs Tell</span>
                      {showTellCount > 0 && <span className="toolbar-analyze-count">{showTellCount}</span>}
                    </button>
                    <button
                      className={`context-menu-item${analysisMode === 'critique' ? ' active' : ''}`}
                      onClick={() => { setAnalyzeOpen(false); void runAIAnalysis('critique') }}
                    >
                      <span>Critique</span>
                      {critiqueCount > 0 && <span className="toolbar-analyze-count">{critiqueCount}</span>}
                    </button>
                  </div>
                )
              })(),
              document.body
            )}
          </>
        )}
      </div>

      <div className="toolbar-right">
        <button
          className={`toolbar-btn toolbar-btn-outline${revisionPanelOpen ? ' active' : ''}`}
          onClick={toggleRevisionPanel}
          title="Revision history"
        >
          ⟳
        </button>
        <button
          className={`toolbar-btn toolbar-btn-outline${outlineOpen ? ' active' : ''}`}
          onClick={toggleOutline}
          title={outlineOpen ? 'Hide document outline' : 'Show document outline'}
        >
          ≡
        </button>
{selectionWordCount !== null && (
          <span className="toolbar-selection-wordcount" title={`${selectionWordCount} words selected`}>
            {formatWordCount(selectionWordCount)} sel
          </span>
        )}
        {activeFilePath && paragraphRhythm.length > 0 && (
          <>
            <button
              ref={rhythmButtonRef}
              className={`toolbar-btn toolbar-btn-outline${rhythmOpen ? ' active' : ''}`}
              onClick={() => setRhythmOpen(v => !v)}
              title="Paragraph rhythm — sentence count per paragraph"
            >
              ∿
            </button>
            {rhythmOpen && rhythmButtonRef.current && createPortal(
              (() => {
                const rect = rhythmButtonRef.current!.getBoundingClientRect()
                return (
                  <div
                    ref={rhythmMenuRef}
                    className="toolbar-rhythm-popover"
                    style={{ top: rect.bottom + 4, right: window.innerWidth - rect.right }}
                  >
                    <div className="toolbar-stats-header">
                      <span className="toolbar-stats-title">Paragraph Rhythm</span>
                      <button className="toolbar-stats-close" onClick={() => setRhythmOpen(false)}>×</button>
                    </div>
                    <div className="toolbar-stats-summary">
                      <span><strong>{paragraphRhythm.length}</strong> paragraphs</span>
                      <span>avg <strong>{Math.round(paragraphRhythm.reduce((s, p) => s + p.sentences, 0) / paragraphRhythm.length * 10) / 10}</strong> sentences</span>
                    </div>
                    <div className="toolbar-rhythm-list">
                      {paragraphRhythm.map((p, i) => {
                        const barW = Math.max(12, Math.round((p.words / maxParaWords) * 180))
                        const color = sentenceCountColor(p.sentences)
                        const preview = p.text.length > 80 ? p.text.slice(0, 80) + '…' : p.text
                        return (
                          <div
                            key={i}
                            className="toolbar-rhythm-row"
                            title={`${p.sentences} sentence${p.sentences !== 1 ? 's' : ''} · ${p.words} words\n${preview}`}
                          >
                            <div
                              className="toolbar-rhythm-bar"
                              style={{ width: barW, background: color }}
                            />
                            <span className="toolbar-rhythm-count" style={{ color }}>{p.sentences}</span>
                          </div>
                        )
                      })}
                    </div>
                    <div className="toolbar-rhythm-legend">
                      {[1, 2, 3, 4, 5, 6, 7, 8].map(n => (
                        <div key={n} className="toolbar-rhythm-legend-item" title={`${n}${n === 8 ? '+' : ''} sentence${n !== 1 ? 's' : ''}`}>
                          <div className="toolbar-rhythm-legend-swatch" style={{ background: sentenceCountColor(n) }} />
                          <span>{n}{n === 8 ? '+' : ''}</span>
                        </div>
                      ))}
                    </div>
                  </div>
                )
              })(),
              document.body
            )}
          </>
        )}

        {activeFilePath && sentenceStats && (
          <>
            <button
              ref={statsButtonRef}
              className={`toolbar-btn toolbar-btn-stats${statsOpen ? ' active' : ''}`}
              onClick={() => setStatsOpen(v => !v)}
              title="Sentence length histogram"
            >
              ≈
            </button>
            {statsOpen && statsButtonRef.current && createPortal(
              (() => {
                const rect = statsButtonRef.current!.getBoundingClientRect()
                const maxBin = Math.max(...sentenceStats.bins, 1)
                const CHART_H = 60
                return (
                  <div
                    ref={statsMenuRef}
                    className="toolbar-stats-popover"
                    style={{ top: rect.bottom + 4, right: window.innerWidth - rect.right }}
                  >
                    <div className="toolbar-stats-header">
                      <span className="toolbar-stats-title">Sentence Lengths</span>
                      <button className="toolbar-stats-close" onClick={() => setStatsOpen(false)}>×</button>
                    </div>
                    <div className="toolbar-stats-summary">
                      <span>avg <strong>{Math.round(sentenceStats.avg * 10) / 10}w</strong></span>
                      <span>σ <strong>{Math.round(sentenceStats.stdDev * 10) / 10}</strong></span>
                      <span><strong>{sentenceStats.totalSentences}</strong> sentences</span>
                    </div>
                    <div className="toolbar-stats-chart" style={{ height: CHART_H }}>
                      {sentenceStats.bins.map((count, i) => {
                        const wordCount = i + 1
                        const isTarget = wordCount >= 11 && wordCount <= 16
                        const barH = count === 0 ? 0 : Math.max(2, Math.round((count / maxBin) * CHART_H))
                        return (
                          <div
                            key={i}
                            className={`toolbar-stats-bar${isTarget ? ' target' : ''}`}
                            style={{ height: barH }}
                            title={`${wordCount === 31 ? '31+' : wordCount}w: ${count} sentence${count !== 1 ? 's' : ''}`}
                          />
                        )
                      })}
                    </div>
                    <div className="toolbar-stats-axis">
                      <span>1</span>
                      <span>8</span>
                      <span className="toolbar-stats-axis-target">11–16 ●</span>
                      <span>22</span>
                      <span>31+</span>
                    </div>
                    {sentenceStats.outliers.length > 0 && (
                      <div className="toolbar-stats-outliers">
                        <div className="toolbar-stats-outliers-title">
                          Flagged (≤4 or ≥26 words)
                        </div>
                        <div className="toolbar-stats-outliers-list">
                          {sentenceStats.outliers.slice(0, 8).map((o, i) => (
                            <div key={i} className="toolbar-stats-outlier">
                              <span className="toolbar-stats-outlier-wc">{o.wordCount}w</span>
                              <span className={`toolbar-stats-outlier-text${o.wordCount <= 4 ? ' short' : ' long'}`}>
                                {o.text.length > 55 ? o.text.slice(0, 55) + '…' : o.text}
                              </span>
                            </div>
                          ))}
                          {sentenceStats.outliers.length > 8 && (
                            <div className="toolbar-stats-outlier-more">
                              +{sentenceStats.outliers.length - 8} more
                            </div>
                          )}
                        </div>
                      </div>
                    )}
                  </div>
                )
              })(),
              document.body
            )}
          </>
        )}
        {activeFilePath && (
          <span
            className="toolbar-wordcount"
            title={`This document: ${docWordCount.toLocaleString()} words · Entire project: ${projectWordCount.toLocaleString()} words${avgSentenceLen !== null ? ` · Avg sentence: ${avgSentenceLen} words` : ''}`}
          >
            {formatWordCount(docWordCount)}
            <span className="toolbar-wordcount-sep">/</span>
            {formatWordCount(projectWordCount)}
            {avgSentenceLen !== null && (
              <>
                <span className="toolbar-wordcount-sep">·</span>
                {avgSentenceLen}w
              </>
            )}
          </span>
        )}
        {isDirty && (
          <span className="toolbar-dirty" title="Unsaved changes — press Cmd+S to save">
            ●
          </span>
        )}
        {activeFilePath && (
          <span className="toolbar-filename" title={activeFilePath.split('/').pop()?.replace(/\.md$/, '')}>
            {(() => {
              const name = activeFilePath.split('/').pop()?.replace(/\.md$/, '') ?? ''
              return name.length > 30 ? name.slice(0, 30) + '…' : name
            })()}
          </span>
        )}
      </div>
    </div>
  )
}
