import { useState, useCallback } from 'react'
import { useWebSocket } from './hooks/useWebSocket'
import Upload from './components/Upload'
import VideoTimeline from './components/VideoTimeline'
import Controls from './components/Controls'

const WS_URL = `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`

type WsMsg =
  | { type: 'segments'; segments: { start: number; end: number }[]; duration: number }
  | { type: 'progress'; percent: number }
  | { type: 'done'; message: string }
  | { type: 'timeline'; segments: { start: number; end: number }[]; duration: number }
  | { type: 'error'; message: string }

type Phase = 'idle' | 'uploading' | 'analyzing' | 'ready' | 'exporting' | 'done'

interface Segment {
  start: number
  end: number
  kept: boolean
}

interface State {
  phase: Phase
  filename: string | null
  videoUrl: string | null   // blob URL for in-browser preview + thumbnail extraction
  duration: number
  segments: Segment[]
  progress: number
  outputFile: string | null
  error: string | null
  noiseDb: number
  minSilence: number
  padding: number
}

const INITIAL: State = {
  phase: 'idle',
  filename: null,
  videoUrl: null,
  duration: 0,
  segments: [],
  progress: 0,
  outputFile: null,
  error: null,
  noiseDb: -30,
  minSilence: 0.5,
  padding: 0.1,
}

export default function App() {
  const [state, setState] = useState<State>(INITIAL)

  const handleMessage = useCallback((raw: unknown) => {
    const msg = raw as WsMsg
    setState((prev) => {
      switch (msg.type) {
        case 'segments':
          return {
            ...prev,
            phase: 'ready',
            duration: msg.duration,
            segments: msg.segments.map((s) => ({ ...s, kept: true })),
          }
        case 'progress':
          return { ...prev, progress: msg.percent }
        case 'done':
          return { ...prev, phase: 'done', outputFile: msg.message, progress: 100 }
        case 'timeline':
          return {
            ...prev,
            phase: 'ready',
            duration: msg.duration,
            segments: msg.segments.map((s) => ({ ...s, kept: true })),
          }
        case 'error':
          return { ...prev, phase: 'ready', error: msg.message }
        default:
          return prev
      }
    })
  }, [])

  useWebSocket(WS_URL, handleMessage)

  // ------------------------------------------------------------------
  // Actions
  // ------------------------------------------------------------------

  const runAnalyze = async (
    filename: string,
    noiseDb: number,
    minSilence: number,
    padding: number,
  ) => {
    setState((prev) => ({ ...prev, phase: 'analyzing', segments: [], outputFile: null, error: null }))
    try {
      const res = await fetch('/analyze', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ filename, noiseDb, minSilence, padding }),
      })
      if (!res.ok) throw new Error(await res.text())
      // Segments stream back via WebSocket → handleMessage
    } catch (e) {
      setState((prev) => ({ ...prev, phase: 'ready', error: String(e) }))
    }
  }

  const handleUpload = async (file: File) => {
    const videoUrl = URL.createObjectURL(file)
    setState((prev) => ({ ...prev, phase: 'uploading', error: null, videoUrl }))
    try {
      const form = new FormData()
      form.append('video', file)
      const res = await fetch('/upload', { method: 'POST', body: form })
      if (!res.ok) throw new Error(await res.text())
      const { filename } = (await res.json()) as { filename: string }
      setState((prev) => ({ ...prev, filename }))
      await runAnalyze(filename, state.noiseDb, state.minSilence, state.padding)
    } catch (e) {
      setState((prev) => ({ ...prev, phase: 'idle', error: String(e) }))
    }
  }

  const handleReanalyze = () => {
    if (!state.filename) return
    runAnalyze(state.filename, state.noiseDb, state.minSilence, state.padding)
  }

  const handleToggle = (index: number) => {
    setState((prev) => ({
      ...prev,
      segments: prev.segments.map((s, i) => (i === index ? { ...s, kept: !s.kept } : s)),
    }))
  }

  const handleExport = async () => {
    if (!state.filename) return
    const kept = state.segments.filter((s) => s.kept).map(({ start, end }) => ({ start, end }))
    setState((prev) => ({ ...prev, phase: 'exporting', progress: 0, outputFile: null, error: null }))
    try {
      const res = await fetch('/export', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ filename: state.filename, segments: kept, duration: state.duration }),
      })
      if (!res.ok) throw new Error(await res.text())
    } catch (e) {
      setState((prev) => ({ ...prev, phase: 'ready', error: String(e) }))
    }
  }

  const handleReset = () => {
    if (state.videoUrl) URL.revokeObjectURL(state.videoUrl)
    setState(INITIAL)
  }

  // ------------------------------------------------------------------
  // Derived
  // ------------------------------------------------------------------

  const keptDuration = state.segments
    .filter((s) => s.kept)
    .reduce((acc, s) => acc + (s.end - s.start), 0)
  const removedDuration = state.duration - keptDuration
  const keptCount = state.segments.filter((s) => s.kept).length

  // Show the video timeline as soon as we have the blob URL
  const showTimeline = state.videoUrl !== null && state.phase !== 'idle'

  return (
    <div className="app">
      <header className="app-header">
        <h1>A-Roll Cutter</h1>
        <p>Automatically removes silence and warm-up from your recordings</p>
      </header>

      <main className="app-main">
        {state.error && (
          <div className="error-banner">
            <span>{state.error}</span>
            <button onClick={() => setState((p) => ({ ...p, error: null }))}>✕</button>
          </div>
        )}

        {/* ── Upload ── */}
        {state.phase === 'idle' && <Upload onUpload={handleUpload} />}

        {/* ── Uploading spinner ── */}
        {state.phase === 'uploading' && (
          <div className="status-card">
            <div className="spinner" />
            <p>Uploading video...</p>
          </div>
        )}

        {/* ── Video preview + timeline (shown as soon as we have the blob URL) ── */}
        {showTimeline && (
          <VideoTimeline
            videoUrl={state.videoUrl!}
            duration={state.duration}
            segments={state.segments}
            onToggle={handleToggle}
            disabled={state.phase !== 'ready'}
          />
        )}

        {/* ── Analyzing overlay (shown below the timeline while we wait) ── */}
        {state.phase === 'analyzing' && (
          <div className="status-card status-card--inline">
            <div className="spinner" />
            <p>Detecting silence...</p>
            <p className="status-sub">FFmpeg is scanning the audio track</p>
          </div>
        )}

        {/* ── Controls (only once we have segments) ── */}
        {(state.phase === 'ready' || state.phase === 'exporting' || state.phase === 'done') && (
          <>
            <Controls
              noiseDb={state.noiseDb}
              minSilence={state.minSilence}
              padding={state.padding}
              disabled={state.phase !== 'ready'}
              onNoiseDb={(v) => setState((p) => ({ ...p, noiseDb: v }))}
              onMinSilence={(v) => setState((p) => ({ ...p, minSilence: v }))}
              onPadding={(v) => setState((p) => ({ ...p, padding: v }))}
              onReanalyze={handleReanalyze}
            />

            <div className="stats">
              <span className="stat stat-kept">Keeping {fmtTime(keptDuration)}</span>
              <span className="stat stat-removed">Removing {fmtTime(removedDuration)}</span>
              <span className="stat stat-total">
                {keptCount} segments · {fmtTime(state.duration)} total
              </span>
            </div>

            {state.phase === 'ready' && (
              <div className="actions">
                <button className="btn-secondary" onClick={handleReset}>
                  Start Over
                </button>
                <button
                  className="btn-primary"
                  onClick={handleExport}
                  disabled={keptCount === 0}
                >
                  Export
                </button>
              </div>
            )}

            {state.phase === 'exporting' && (
              <div className="progress-section">
                <p className="progress-label">Exporting... {Math.round(state.progress)}%</p>
                <div className="progress-track">
                  <div className="progress-fill" style={{ width: `${state.progress}%` }} />
                </div>
              </div>
            )}

            {state.outputFile && (
              <div className="done-panel">
                <span className="done-check">✓</span>
                <p>Export complete!</p>
                <a href={`/download/${state.outputFile}`} download className="btn-primary">
                  Download
                </a>
                <button className="btn-secondary" onClick={handleReset}>
                  Process Another
                </button>
              </div>
            )}
          </>
        )}
      </main>
    </div>
  )
}

function fmtTime(s: number): string {
  const m = Math.floor(s / 60)
  const sec = Math.floor(s % 60)
  return m > 0 ? `${m}m ${sec}s` : `${sec}s`
}
