import { useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { useEditorStore } from '../../store/editorStore'
import { detectPassiveVoice } from '../../utils/passiveVoice'
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)
}

function computeAvgSentenceLength(text: string): number | null {
  const sentences = text
    .split(/[.!?]+/)
    .map(s => s.trim())
    .filter(s => s.length > 0)
  if (sentences.length === 0) return null
  const totalWords = sentences.reduce((sum, s) => sum + countWords(s), 0)
  return Math.round((totalWords / sentences.length) * 10) / 10
}

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

  const [analyzeOpen, setAnalyzeOpen] = useState(false)
  const analyzeButtonRef = useRef<HTMLButtonElement>(null)
  const analyzeMenuRef = 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 dropdown on file change
  useEffect(() => { setAnalyzeOpen(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 dropdown
  useEffect(() => {
    if (!analyzeOpen) return
    const handler = (e: KeyboardEvent): void => { if (e.key === 'Escape') setAnalyzeOpen(false) }
    document.addEventListener('keydown', handler)
    return () => document.removeEventListener('keydown', handler)
  }, [analyzeOpen])

  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')

    addUserMessage(prompt)
    startAssistantMessage({ bibleGeneration: true })
    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) => {
          appendToLastAssistantMessage(chunk)
        }
      )
    } 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 runAIAnalysis = async (mode: 'consistency' | 'style' | 'show_tell' | 'critique'): 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.'
            : 'Please give me an honest critique of this chapter.'

    addUserMessage(prompt)
    startAssistantMessage()
    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) => {
          appendToLastAssistantMessage(chunk)
        }
      )

      // Parse annotations from response
      const currentHistory = useEditorStore.getState().chatHistory
      const lastMsg = currentHistory[currentHistory.length - 1]
      if (lastMsg?.role === 'assistant' && lastMsg.content.length > 0) {
        // For show_tell mode, force all annotations to the show_tell type so the
        // classifier doesn't accidentally mis-label them as 'style' or 'consistency'.
        const overrideType = mode === 'show_tell' ? 'show_tell' : undefined
        const { annotations: newAnnotations } = parseAnnotationsFromAIResponse(lastMsg.content, activeFileContent, overrideType)
        if (newAnnotations.length > 0) {
          const existing = useEditorStore.getState().annotations.filter((a) => a.type !== mode)
          setAnnotations([...existing, ...newAnnotations])
          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 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 + consistencyCount + styleCount + showTellCount + critiqueCount
  const anyActive = Boolean(analysisMode)
  const docWordCount = countWords(activeFileContent)
  const avgSentenceLen = activeFileContent ? computeAvgSentenceLength(activeFileContent) : null

  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 === '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>
        <div className="toolbar-fontsize">
          <button
            className="toolbar-fontsize-btn"
            onClick={() => setFontSize(fontSize - 1)}
            disabled={fontSize <= 11}
            title="Decrease font size"
          >
            A−
          </button>
          <button
            className="toolbar-fontsize-btn"
            onClick={() => setFontSize(fontSize + 1)}
            disabled={fontSize >= 24}
            title="Increase font size"
          >
            A+
          </button>
        </div>
        {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>
  )
}
