import React, { useState, useRef, useEffect } from 'react';
import {
  Upload, Activity, Heart, FileAudio,
  CheckCircle, AlertTriangle, RefreshCw,
  Mic, Square, Download, Cpu, Sun, Moon, Menu, X
} from 'lucide-react';
import jsPDF from 'jspdf';
import './App.css';

// ─── Waveform Canvas with Time Axis + Heartbeat Markers ──────────────────────
// Waveform Canvas: static bottom layer + live animated overlay
function WaveformCanvas({ waveform, peakVisIndices, peakTimesSec, duration, isDisease, canvasRefOut, audioRef }) {
  const staticRef = useRef(null);
  const overlayRef = useRef(null);
  const rafRef = useRef(null);
  const accentColor = isDisease ? '#ef4444' : '#06b6d4';

  const PAD = { L: 42, R: 12, T: 12, B: 36 };

  // Static draw: runs once when waveform data changes
  useEffect(() => {
    const canvas = staticRef.current;
    if (!canvas || !waveform || waveform.length === 0) return;
    if (canvasRefOut) canvasRefOut.current = canvas;
    const dpr = window.devicePixelRatio || 1;
    const W = canvas.offsetWidth, H = canvas.offsetHeight;
    canvas.width = W * dpr; canvas.height = H * dpr;
    const ctx = canvas.getContext('2d');
    ctx.scale(dpr, dpr);

    const { L, R, T, B } = PAD;
    const cW = W - L - R, cH = H - B - T;
    const n = waveform.length;
    const xOf = (i) => L + (i / (n - 1)) * cW;
    const yOf = (v) => T + cH / 2 - v * cH * 0.42;

    ctx.fillStyle = 'rgba(5,8,18,1)'; ctx.fillRect(0, 0, W, H);
    ctx.strokeStyle = 'rgba(255,255,255,0.04)'; ctx.lineWidth = 1;
    for (let i = 0; i <= 4; i++) {
      const y = T + (cH * i) / 4;
      ctx.beginPath(); ctx.moveTo(L, y); ctx.lineTo(L + cW, y); ctx.stroke();
    }

    const grad = ctx.createLinearGradient(0, T, 0, T + cH);
    grad.addColorStop(0, isDisease ? 'rgba(239,68,68,0.5)' : 'rgba(6,182,212,0.5)');
    grad.addColorStop(0.5, isDisease ? 'rgba(239,68,68,0.08)' : 'rgba(6,182,212,0.08)');
    grad.addColorStop(1, 'rgba(0,0,0,0)');
    ctx.beginPath();
    ctx.moveTo(xOf(0), yOf(waveform[0]));
    for (let i = 1; i < n; i++) ctx.lineTo(xOf(i), yOf(waveform[i]));
    ctx.lineTo(xOf(n - 1), T + cH / 2); ctx.lineTo(xOf(0), T + cH / 2);
    ctx.closePath(); ctx.fillStyle = grad; ctx.fill();

    ctx.beginPath();
    ctx.moveTo(xOf(0), yOf(waveform[0]));
    for (let i = 1; i < n; i++) ctx.lineTo(xOf(i), yOf(waveform[i]));
    ctx.strokeStyle = accentColor; ctx.lineWidth = 1.8;
    ctx.shadowBlur = 8; ctx.shadowColor = isDisease ? 'rgba(239,68,68,0.4)' : 'rgba(6,182,212,0.4)';
    ctx.stroke(); ctx.shadowBlur = 0;

    if (peakVisIndices && peakVisIndices.length > 0) {
      peakVisIndices.forEach((pidx, i) => {
        const x = xOf(pidx);
        ctx.setLineDash([3, 4]); ctx.strokeStyle = 'rgba(255,255,255,0.2)'; ctx.lineWidth = 1;
        ctx.beginPath(); ctx.moveTo(x, T + 4); ctx.lineTo(x, T + cH); ctx.stroke();
        ctx.setLineDash([]);
        ctx.save(); ctx.translate(x, T + 6); ctx.rotate(Math.PI / 4);
        ctx.fillStyle = accentColor; ctx.fillRect(-4, -4, 8, 8); ctx.restore();
        if (peakTimesSec && peakTimesSec[i] !== undefined && (peakVisIndices.length < 30 || i % 2 === 0)) {
          ctx.fillStyle = 'rgba(255,255,255,0.5)'; ctx.font = '9px monospace';
          ctx.textAlign = 'center'; ctx.fillText(peakTimesSec[i].toFixed(1) + 's', x, T + 22);
        }
      });
    }

    const axisY = T + cH + 6;
    ctx.strokeStyle = 'rgba(255,255,255,0.15)'; ctx.lineWidth = 1;
    ctx.beginPath(); ctx.moveTo(L, axisY); ctx.lineTo(L + cW, axisY); ctx.stroke();
    const numTicks = Math.min(12, Math.floor(duration));
    for (let t = 0; t <= numTicks; t++) {
      const ts = (t / numTicks) * duration;
      const x = L + (ts / duration) * cW;
      ctx.beginPath(); ctx.moveTo(x, axisY); ctx.lineTo(x, axisY + 5); ctx.stroke();
      ctx.fillStyle = 'rgba(255,255,255,0.5)'; ctx.font = '10px monospace';
      ctx.textAlign = 'center'; ctx.fillText(ts.toFixed(0) + 's', x, axisY + 16);
    }
    ctx.fillStyle = 'rgba(255,255,255,0.3)'; ctx.font = '10px sans-serif';
    ctx.textAlign = 'left'; ctx.fillText('Time (seconds)', L, axisY + 30);
    ctx.save(); ctx.translate(12, T + cH / 2); ctx.rotate(-Math.PI / 2);
    ctx.fillStyle = 'rgba(255,255,255,0.3)'; ctx.font = '10px sans-serif';
    ctx.textAlign = 'center'; ctx.fillText('Amplitude', 0, 0); ctx.restore();

  }, [waveform, peakVisIndices, peakTimesSec, duration, isDisease]);

  // Animation loop: playhead + beat pulse (runs while audio plays)
  useEffect(() => {
    const audio = audioRef?.current;
    const overlay = overlayRef.current;
    if (!overlay || !audio || !duration) return;

    const { L, R, T, B } = PAD;
    const BEAT_WIN = 0.35; // seconds a beat glows after being crossed

    const drawOverlay = () => {
      const dpr = window.devicePixelRatio || 1;
      const W = overlay.offsetWidth, H = overlay.offsetHeight;
      if (overlay.width !== Math.round(W * dpr)) overlay.width = Math.round(W * dpr);
      if (overlay.height !== Math.round(H * dpr)) overlay.height = Math.round(H * dpr);
      const ctx = overlay.getContext('2d');
      ctx.save();
      ctx.clearRect(0, 0, overlay.width, overlay.height);
      ctx.scale(dpr, dpr);

      const cW = W - L - R, cH = H - B - T;
      const n = waveform ? waveform.length : 1;
      const t = audio.currentTime;

      if (t > 0 && cW > 0) {
        const px = L + (t / duration) * cW;

        // Scanned region overlay
        ctx.fillStyle = 'rgba(255,255,255,0.025)';
        ctx.fillRect(L, T, px - L, cH);

        // White glowing playhead
        ctx.save();
        ctx.strokeStyle = 'rgba(255,255,255,0.92)'; ctx.lineWidth = 1.5;
        ctx.shadowBlur = 10; ctx.shadowColor = 'rgba(255,255,255,0.8)';
        ctx.beginPath(); ctx.moveTo(px, T); ctx.lineTo(px, T + cH); ctx.stroke();
        ctx.restore();

        // Beat pulse glows
        if (peakTimesSec && peakVisIndices) {
          peakTimesSec.forEach((beatT, i) => {
            const diff = t - beatT;
            if (diff < 0 || diff > BEAT_WIN) return;
            const alpha = 1 - diff / BEAT_WIN;
            const bx = L + (peakVisIndices[i] / (n - 1)) * cW;

            // Radial halo
            ctx.save();
            const rg = ctx.createRadialGradient(bx, T + cH / 2, 0, bx, T + cH / 2, 40);
            rg.addColorStop(0, isDisease ? `rgba(239,68,68,${alpha * 0.55})` : `rgba(6,182,212,${alpha * 0.55})`);
            rg.addColorStop(1, 'rgba(0,0,0,0)');
            ctx.fillStyle = rg;
            ctx.fillRect(bx - 42, T, 84, cH);
            ctx.restore();

            // Pulsing diamond
            const size = 5 + alpha * 10;
            ctx.save();
            ctx.translate(bx, T + cH / 2);
            ctx.rotate(Math.PI / 4);
            ctx.globalAlpha = alpha;
            ctx.fillStyle = accentColor;
            ctx.shadowBlur = 22 * alpha; ctx.shadowColor = accentColor;
            ctx.fillRect(-size / 2, -size / 2, size, size);
            ctx.restore();

            // Beat number label
            ctx.save();
            ctx.globalAlpha = alpha * 0.85;
            ctx.fillStyle = 'white'; ctx.font = 'bold 11px monospace';
            ctx.textAlign = 'center';
            ctx.fillText('\u2665 ' + (i + 1), bx, T + cH / 2 + 22);
            ctx.restore();
          });
        }
      }

      ctx.restore();
      rafRef.current = requestAnimationFrame(drawOverlay);
    };

    const startLoop = () => {
      if (!rafRef.current) rafRef.current = requestAnimationFrame(drawOverlay);
    };
    const stopLoop = () => {
      if (rafRef.current) { cancelAnimationFrame(rafRef.current); rafRef.current = null; }
      const ctx = overlay.getContext('2d');
      if (ctx) ctx.clearRect(0, 0, overlay.width, overlay.height);
    };

    audio.addEventListener('play', startLoop);
    audio.addEventListener('pause', stopLoop);
    audio.addEventListener('ended', stopLoop);
    audio.addEventListener('seeked', () => { if (!audio.paused) startLoop(); });

    return () => {
      stopLoop();
      audio.removeEventListener('play', startLoop);
      audio.removeEventListener('pause', stopLoop);
      audio.removeEventListener('ended', stopLoop);
    };
  }, [waveform, peakVisIndices, peakTimesSec, duration, isDisease, audioRef]);

  return (
    <div style={{ position: 'relative', width: '100%', height: '100%' }}>
      <canvas ref={staticRef} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', display: 'block' }} />
      <canvas ref={overlayRef} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', display: 'block', pointerEvents: 'none' }} />
    </div>
  );
}


// Module-level WAV encoder (used by both recording and trimmer)
function bufferToWave(abuffer, startSample, numSamples) {
  const numChan = abuffer.numberOfChannels;
  const sr = abuffer.sampleRate;
  const byteLen = numSamples * numChan * 2 + 44;
  const buf = new ArrayBuffer(byteLen);
  const view = new DataView(buf);
  let pos = 0;
  const w16 = (v) => { view.setUint16(pos, v, true); pos += 2; };
  const w32 = (v) => { view.setUint32(pos, v, true); pos += 4; };
  w32(0x46464952); w32(byteLen - 8); w32(0x45564157);
  w32(0x20746d66); w32(16); w16(1); w16(numChan);
  w32(sr); w32(sr * 2 * numChan); w16(numChan * 2); w16(16);
  w32(0x61746164); w32(byteLen - pos - 4);
  const channels = [];
  for (let c = 0; c < numChan; c++) channels.push(abuffer.getChannelData(c));
  for (let i = 0; i < numSamples; i++) {
    for (let c = 0; c < numChan; c++) {
      let s = Math.max(-1, Math.min(1, channels[c][startSample + i]));
      s = (0.5 + s < 0 ? s * 32768 : s * 32767) | 0;
      view.setInt16(pos, s, true); pos += 2;
    }
  }
  return new Blob([buf], { type: 'audio/wav' });
}

// Decode any audio blob and return { waveform (Float32Array), duration, buffer }
async function decodeAudioBlob(blob) {
  const arrayBuffer = await blob.arrayBuffer();
  const ctx = new (window.AudioContext || window.webkitAudioContext)();
  const audioBuffer = await ctx.decodeAudioData(arrayBuffer);
  await ctx.close();
  return audioBuffer;
}

// Downsample a Float32Array to ~800 points for display
function downsample(data, points = 800) {
  const step = Math.max(1, Math.floor(data.length / points));
  const out = [];
  for (let i = 0; i < data.length; i += step) out.push(data[i]);
  return out;
}

// ─── Audio Trimmer ─────────────────────────────────────────────────────────────
function AudioTrimmer({ waveform, duration, onAnalyze, onSkip }) {
  const canvasRef = useRef(null);
  const [startFrac, setStartFrac] = useState(0);
  const [endFrac, setEndFrac] = useState(1);
  const dragging = useRef(null); // 'start' | 'end' | null
  const stateRef = useRef({ startFrac: 0, endFrac: 1 });

  const PAD = { L: 16, R: 16, T: 24, B: 28 };

  // Keep stateRef in sync for RAF access inside mouse handlers
  useEffect(() => { stateRef.current = { startFrac, endFrac }; }, [startFrac, endFrac]);

  // Draw whenever state or waveform changes
  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas || !waveform || waveform.length === 0) return;
    const dpr = window.devicePixelRatio || 1;
    const W = canvas.offsetWidth, H = canvas.offsetHeight;
    canvas.width = W * dpr; canvas.height = H * dpr;
    const ctx = canvas.getContext('2d');
    ctx.scale(dpr, dpr);
    const { L, R, T, B } = PAD;
    const cW = W - L - R, cH = H - T - B;
    const n = waveform.length;
    const xOf = (i) => L + (i / (n - 1)) * cW;
    const yOf = (v) => T + cH / 2 - v * cH * 0.42;
    const sX = L + startFrac * cW;
    const eX = L + endFrac * cW;

    // Background
    ctx.fillStyle = 'rgba(5,8,18,1)'; ctx.fillRect(0, 0, W, H);

    // Waveform (dimmed outside selection)
    for (let i = 1; i < n; i++) {
      const x0 = xOf(i - 1), x1 = xOf(i);
      const inside = x0 >= sX && x1 <= eX;
      ctx.strokeStyle = inside ? '#06b6d4' : 'rgba(255,255,255,0.12)';
      ctx.lineWidth = inside ? 1.8 : 1;
      ctx.shadowBlur = inside ? 6 : 0;
      ctx.shadowColor = '#06b6d4';
      ctx.beginPath(); ctx.moveTo(x0, yOf(waveform[i - 1])); ctx.lineTo(x1, yOf(waveform[i])); ctx.stroke();
    }
    ctx.shadowBlur = 0;

    // Dim excluded zones
    ctx.fillStyle = 'rgba(5,8,18,0.6)';
    ctx.fillRect(L, T, sX - L, cH);
    ctx.fillRect(eX, T, L + cW - eX, cH);

    // Selection highlight box
    ctx.strokeStyle = 'rgba(6,182,212,0.4)'; ctx.lineWidth = 1;
    ctx.strokeRect(sX, T, eX - sX, cH);
    ctx.fillStyle = 'rgba(6,182,212,0.05)'; ctx.fillRect(sX, T, eX - sX, cH);

    // Draw handles (vertical bar with grip arrows)
    [[sX, 'start'], [eX, 'end']].forEach(([x, side]) => {
      ctx.fillStyle = '#06b6d4';
      ctx.fillRect(x - 2, T, 4, cH);
      // Arrow triangle on handle
      ctx.fillStyle = 'white';
      const dir = side === 'start' ? 1 : -1;
      ctx.beginPath();
      ctx.moveTo(x + dir * 2, T + cH / 2);
      ctx.lineTo(x + dir * 10, T + cH / 2 - 7);
      ctx.lineTo(x + dir * 10, T + cH / 2 + 7);
      ctx.closePath(); ctx.fill();
    });

    // Time labels on handles
    ctx.fillStyle = 'rgba(255,255,255,0.85)'; ctx.font = 'bold 11px monospace';
    ctx.textAlign = 'center';
    ctx.fillText((startFrac * duration).toFixed(2) + 's', sX, T - 6);
    ctx.fillText((endFrac * duration).toFixed(2) + 's', eX, T - 6);

    // Bottom axis
    const axisY = T + cH + 6;
    ctx.strokeStyle = 'rgba(255,255,255,0.12)'; ctx.lineWidth = 1;
    ctx.beginPath(); ctx.moveTo(L, axisY); ctx.lineTo(L + cW, axisY); ctx.stroke();
    const numTicks = Math.min(10, Math.floor(duration));
    for (let t = 0; t <= numTicks; t++) {
      const x = L + (t / numTicks) * cW;
      ctx.fillStyle = 'rgba(255,255,255,0.4)'; ctx.font = '9px monospace';
      ctx.textAlign = 'center'; ctx.fillText(((t / numTicks) * duration).toFixed(0) + 's', x, axisY + 14);
    }

    // Selection duration label in center
    const selSec = ((endFrac - startFrac) * duration).toFixed(1);
    ctx.fillStyle = 'rgba(6,182,212,0.9)'; ctx.font = 'bold 12px sans-serif';
    ctx.textAlign = 'center';
    ctx.fillText(`Selection: ${selSec}s`, L + cW / 2, T + cH / 2 - 14);

  }, [waveform, duration, startFrac, endFrac]);

  // Mouse interaction
  const fracFromX = (canvas, clientX) => {
    const rect = canvas.getBoundingClientRect();
    const { L, R } = PAD;
    const cW = rect.width - L - R;
    return Math.max(0, Math.min(1, (clientX - rect.left - L) / cW));
  };

  const onMouseDown = (e) => {
    const canvas = canvasRef.current;
    const f = fracFromX(canvas, e.clientX);
    const { startFrac: s, endFrac: en } = stateRef.current;
    const dS = Math.abs(f - s), dE = Math.abs(f - en);
    dragging.current = dS < dE ? 'start' : 'end';
  };

  const onMouseMove = (e) => {
    if (!dragging.current) return;
    const f = fracFromX(canvasRef.current, e.clientX);
    const { startFrac: s, endFrac: en } = stateRef.current;
    if (dragging.current === 'start') setStartFrac(Math.min(f, en - 0.01));
    else setEndFrac(Math.max(f, s + 0.01));
  };

  const onMouseUp = () => { dragging.current = null; };

  // Touch support
  const onTouchStart = (e) => onMouseDown(e.touches[0]);
  const onTouchMove = (e) => { e.preventDefault(); onMouseMove(e.touches[0]); };
  const onTouchEnd = () => onMouseUp();

  return (
    <div>
      <canvas ref={canvasRef}
        style={{ width: '100%', height: '200px', display: 'block', cursor: 'col-resize', borderRadius: '8px', overflow: 'hidden' }}
        onMouseDown={onMouseDown} onMouseMove={onMouseMove} onMouseUp={onMouseUp} onMouseLeave={onMouseUp}
        onTouchStart={onTouchStart} onTouchMove={onTouchMove} onTouchEnd={onTouchEnd}
      />
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: '16px', flexWrap: 'wrap', gap: '12px' }}>
        <div style={{ fontSize: '0.85rem', color: 'var(--text-secondary)' }}>
          <span style={{ color: '#06b6d4', fontWeight: 600 }}>✂ Drag the handles</span> to select the clean cardiac section
        </div>
        <div style={{ display: 'flex', gap: '12px' }}>
          <button className="btn-secondary" onClick={onSkip} style={{ fontSize: '0.9rem' }}>
            Use Full Recording
          </button>
          <button className="btn-primary" style={{ background: 'var(--accent-cyan)', color: '#000', padding: '10px 20px', borderRadius: '8px', fontWeight: 700, border: 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: '8px', fontSize: '0.9rem' }}
            onClick={() => onAnalyze(startFrac, endFrac)}>
            ✂ Analyze Selection
          </button>
        </div>
      </div>
    </div>
  );
}

const API_URL = (import.meta.env.VITE_API_URL) ?? "http://127.0.0.1:8000/analyze";

function App() {
  // ── All useState hooks first (React rules of hooks) ──────
  const [appState, setAppState] = useState('upload');
  const [patientData, setPatientData] = useState({ dogId: '', breed: '', age: '' });
  const [analysisResult, setAnalysisResult] = useState(null);
  const [isRecording, setIsRecording] = useState(false);
  const [recordingTime, setRecordingTime] = useState(0);
  const [audioBlob, setAudioBlob] = useState(null);
  const [audioUrl, setAudioUrl] = useState(null);
  const [trimWaveform, setTrimWaveform] = useState(null);
  const [trimDuration, setTrimDuration] = useState(0);
  const [theme, setTheme] = useState('dark');
  const [mobileNavOpen, setMobileNavOpen] = useState(false);

  // ── All useRef hooks next ─────────────────────────────────
  const rawAudioBuffer = useRef(null);


  const audioContextRef = useRef(null);
  const analyserRef = useRef(null);
  const mediaStreamRef = useRef(null);
  const sourceRef = useRef(null);
  const animationFrameRef = useRef(null);
  const canvasRef = useRef(null);
  const timerRef = useRef(null);
  const mediaRecorderRef = useRef(null);
  const audioChunksRef = useRef([]);
  const waveformCanvasRef = useRef(null);
  const audioRef = useRef(null);

  // Apply theme attribute to <html> element
  useEffect(() => {
    document.documentElement.setAttribute('data-theme', theme);
  }, [theme]);

  const toggleTheme = () => setTheme(t => t === 'dark' ? 'light' : 'dark');
  const closeMobileNav = () => setMobileNavOpen(false);

  const stopRecording = () => {
    if (mediaRecorderRef.current && mediaRecorderRef.current.state !== 'inactive') {
      mediaRecorderRef.current.stop();
    }
    if (mediaStreamRef.current) {
      mediaStreamRef.current.getTracks().forEach(track => track.stop());
      mediaStreamRef.current = null;
    }
    if (audioContextRef.current && audioContextRef.current.state !== 'closed') {
      audioContextRef.current.close().catch(console.error);
      audioContextRef.current = null;
    }
    if (animationFrameRef.current) cancelAnimationFrame(animationFrameRef.current);
    if (timerRef.current) clearInterval(timerRef.current);
    setIsRecording(false);
  };

  const startRecording = async () => {
    if (!patientData.dogId) {
      alert("Please enter a Dog ID first.");
      return;
    }
    try {
      setAppState('recording');
      setIsRecording(true);
      setRecordingTime(0);
      audioChunksRef.current = [];

      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      mediaStreamRef.current = stream;

      mediaRecorderRef.current = new MediaRecorder(stream);
      mediaRecorderRef.current.ondataavailable = (event) => {
        if (event.data.size > 0) audioChunksRef.current.push(event.data);
      };

      mediaRecorderRef.current.onstop = async () => {
        const rawBlob = new Blob(audioChunksRef.current);
        const audioBuffer = await decodeAudioBlob(rawBlob);
        rawAudioBuffer.current = audioBuffer;
        const wavBlob = bufferToWave(audioBuffer, 0, audioBuffer.length);
        setAudioBlob(wavBlob);
        setAudioUrl(URL.createObjectURL(wavBlob));
        const wf = downsample(audioBuffer.getChannelData(0));
        setTrimWaveform(wf);
        setTrimDuration(audioBuffer.duration);
        setAppState('trimming');
      };

      mediaRecorderRef.current.start();

      audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
      analyserRef.current = audioContextRef.current.createAnalyser();
      analyserRef.current.fftSize = 2048;
      sourceRef.current = audioContextRef.current.createMediaStreamSource(stream);
      sourceRef.current.connect(analyserRef.current);
      drawWaveform();

      timerRef.current = setInterval(() => setRecordingTime((prev) => prev + 1), 1000);

    } catch (err) {
      console.error("Microphone access error:", err);
      alert("Microphone access denied or unavailable.");
      setAppState('upload');
      setIsRecording(false);
    }
  };

  const drawWaveform = () => {
    if (!canvasRef.current || !analyserRef.current) {
      animationFrameRef.current = requestAnimationFrame(drawWaveform);
      return;
    }
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    const analyser = analyserRef.current;
    const bufferLength = analyser.frequencyBinCount;
    const dataArray = new Uint8Array(bufferLength);
    analyser.getByteTimeDomainData(dataArray);

    ctx.fillStyle = 'rgba(11, 15, 25, 1)';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.lineWidth = 3;
    ctx.strokeStyle = '#06b6d4';
    ctx.shadowBlur = 10;
    ctx.shadowColor = '#06b6d4';
    ctx.beginPath();

    const sliceWidth = canvas.width / bufferLength;
    let x = 0;
    for (let i = 0; i < bufferLength; i++) {
      const v = dataArray[i] / 128.0;
      const y = v * canvas.height / 2;
      i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
      x += sliceWidth;
    }
    ctx.lineTo(canvas.width, canvas.height / 2);
    ctx.stroke();
    animationFrameRef.current = requestAnimationFrame(drawWaveform);
  };

  const handleFinishRecording = () => {
    setAppState('analyzing'); // will be overridden to 'trimming' once audio decoded in onstop
    stopRecording();
  };

  const handleManualUpload = () => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'audio/*';
    input.onchange = async (e) => {
      const file = e.target.files[0];
      if (!file) return;
      if (!patientData.dogId) { alert('Please enter a Dog ID first.'); return; }
      const audioBuffer = await decodeAudioBlob(file);
      rawAudioBuffer.current = audioBuffer;
      const wavBlob = bufferToWave(audioBuffer, 0, audioBuffer.length);
      setAudioBlob(wavBlob);
      setAudioUrl(URL.createObjectURL(wavBlob));
      const wf = downsample(audioBuffer.getChannelData(0));
      setTrimWaveform(wf);
      setTrimDuration(audioBuffer.duration);
      setAppState('trimming');
    };
    input.click();
  };

  const handleAnalyzeTrimmed = (startFrac, endFrac) => {
    const ab = rawAudioBuffer.current;
    if (!ab) return;
    const startSample = Math.floor(startFrac * ab.length);
    const numSamples = Math.floor((endFrac - startFrac) * ab.length);
    const trimmedBlob = bufferToWave(ab, startSample, numSamples);
    // Update the stored audio blob/url to the trimmed version
    if (audioUrl) URL.revokeObjectURL(audioUrl);
    const newUrl = URL.createObjectURL(trimmedBlob);
    setAudioBlob(trimmedBlob);
    setAudioUrl(newUrl);
    setAppState('analyzing');
    sendToBackend(trimmedBlob);
  };

  const handleSkipTrim = () => {
    setAppState('analyzing');
    sendToBackend(audioBlob);
  };

  const sendToBackend = async (audioBlob) => {
    try {
      const formData = new FormData();
      formData.append('file', audioBlob, 'recording.wav');

      const response = await fetch(API_URL, { method: "POST", body: formData });
      const result = await response.json();
      console.log("Backend response:", result);

      if (result.error) throw new Error(result.error);

      let bpmStatus = "Normal";
      let bpmColor = "var(--success)";
      if (result.bpm > 140) { bpmStatus = "High (Tachycardia?)"; bpmColor = "var(--danger)"; }
      else if (result.bpm < 60 && result.bpm > 0) { bpmStatus = "Low (Bradycardia?)"; bpmColor = "var(--warning)"; }
      else if (result.bpm === 0) { bpmStatus = "Undetected"; bpmColor = "var(--text-secondary)"; }

      const waveformData = result.waveform.map((amp, idx) => ({ time: idx, amplitude: amp }));

      setAnalysisResult({
        ...result,
        bpmStatus,
        bpmColor,
        waveformData,
      });
      setAppState('dashboard');

    } catch (error) {
      console.error("Analysis error:", error);
      alert(`Analysis failed: ${error.message}\n\nCheck if api.py is running.`);
      resetApp();
    }
  };

  const downloadAudio = () => {
    if (!audioBlob) return;
    const url = URL.createObjectURL(audioBlob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `heart_sound_${patientData.dogId}_${Date.now()}.wav`;
    a.click();
    URL.revokeObjectURL(url);
  };

  const downloadReport = async () => {
    if (!analysisResult) return;
    const r = analysisResult;
    const ai = r.ai_classification;
    const now = new Date().toLocaleString();
    const isMurmur = ai.is_disease;
    const pdf = new jsPDF('p', 'mm', 'a4');
    const W = 210, H = 297;
    const marginL = 18, marginR = 18;
    const contentW = W - marginL - marginR;
    let y = 0;

    // === HEADER BAND ===
    pdf.setFillColor(15, 23, 42);
    pdf.rect(0, 0, W, 38, 'F');
    // Accent line
    pdf.setFillColor(isMurmur ? 239 : 6, isMurmur ? 68 : 182, isMurmur ? 68 : 212);
    pdf.rect(0, 38, W, 2, 'F');
    // Title
    pdf.setTextColor(255, 255, 255);
    pdf.setFont('helvetica', 'bold'); pdf.setFontSize(20);
    pdf.text('CardioScreen AI', marginL, 18);
    pdf.setFont('helvetica', 'normal'); pdf.setFontSize(10);
    pdf.setTextColor(148, 163, 184);
    pdf.text('Canine Cardiac Screening Report', marginL, 26);
    // Date right-aligned
    pdf.setFontSize(9); pdf.setTextColor(148, 163, 184);
    pdf.text(now, W - marginR, 18, { align: 'right' });
    pdf.text(`Patient: ${patientData.dogId}`, W - marginR, 26, { align: 'right' });
    y = 48;

    // === RESULT BANNER ===
    pdf.setFillColor(isMurmur ? 254 : 240, isMurmur ? 242 : 253, isMurmur ? 242 : 250);
    pdf.roundedRect(marginL, y, contentW, 28, 3, 3, 'F');
    pdf.setDrawColor(isMurmur ? 239 : 34, isMurmur ? 68 : 197, isMurmur ? 68 : 94);
    pdf.roundedRect(marginL, y, contentW, 28, 3, 3, 'S');
    pdf.setFontSize(16); pdf.setFont('helvetica', 'bold');
    pdf.setTextColor(isMurmur ? 185 : 21, isMurmur ? 28 : 128, isMurmur ? 28 : 61);
    pdf.text(isMurmur ? '⚠ MURMUR DETECTED' : '✓ NORMAL HEART SOUND', marginL + 8, y + 12);
    pdf.setFontSize(10); pdf.setFont('helvetica', 'normal');
    pdf.setTextColor(100, 100, 100);
    pdf.text(`Confidence: ${(ai.confidence * 100).toFixed(1)}%`, marginL + 8, y + 22);
    // BPM right side
    pdf.setFontSize(22); pdf.setFont('helvetica', 'bold');
    pdf.setTextColor(isMurmur ? 185 : 21, isMurmur ? 28 : 128, isMurmur ? 28 : 61);
    pdf.text(`${r.bpm}`, W - marginR - 30, y + 14, { align: 'right' });
    pdf.setFontSize(9); pdf.setFont('helvetica', 'normal');
    pdf.setTextColor(100, 100, 100);
    pdf.text('BPM', W - marginR - 8, y + 14, { align: 'right' });
    pdf.text(`${r.bpmStatus}`, W - marginR - 8, y + 22, { align: 'right' });
    y += 36;

    // === PATIENT INFO TABLE ===
    pdf.setFontSize(11); pdf.setFont('helvetica', 'bold');
    pdf.setTextColor(30, 41, 59);
    pdf.text('Patient Information', marginL, y);
    y += 6;
    pdf.setFillColor(248, 250, 252);
    pdf.rect(marginL, y, contentW, 22, 'F');
    pdf.setDrawColor(226, 232, 240);
    pdf.rect(marginL, y, contentW, 22, 'S');
    pdf.setFontSize(9); pdf.setFont('helvetica', 'normal');
    pdf.setTextColor(71, 85, 105);
    const col1 = marginL + 5, col2 = marginL + 50, col3 = marginL + 95, col4 = marginL + 130;
    pdf.text('Dog ID:', col1, y + 8); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(30, 41, 59); pdf.text(patientData.dogId, col1, y + 15);
    pdf.setFont('helvetica', 'normal'); pdf.setTextColor(71, 85, 105);
    pdf.text('Breed:', col2, y + 8); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(30, 41, 59); pdf.text(patientData.breed || 'N/A', col2, y + 15);
    pdf.setFont('helvetica', 'normal'); pdf.setTextColor(71, 85, 105);
    pdf.text('Age:', col3, y + 8); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(30, 41, 59); pdf.text(patientData.age ? `${patientData.age} years` : 'N/A', col3, y + 15);
    pdf.setFont('helvetica', 'normal'); pdf.setTextColor(71, 85, 105);
    pdf.text('Duration:', col4, y + 8); pdf.setFont('helvetica', 'bold'); pdf.setTextColor(30, 41, 59); pdf.text(`${r.duration_seconds}s (${r.heartbeat_count} beats)`, col4, y + 15);
    y += 30;

    // === WAVEFORM IMAGE ===
    pdf.setFontSize(11); pdf.setFont('helvetica', 'bold');
    pdf.setTextColor(30, 41, 59);
    pdf.text('Phonocardiogram', marginL, y);
    y += 4;
    if (waveformCanvasRef.current) {
      try {
        const imgData = waveformCanvasRef.current.toDataURL('image/png');
        const imgW = contentW;
        const imgH = imgW * 0.35;
        pdf.addImage(imgData, 'PNG', marginL, y, imgW, imgH);
        y += imgH + 4;
      } catch (e) { console.warn('Could not capture waveform:', e); y += 4; }
    } else { y += 4; }

    // === PROBABILITY BREAKDOWN ===
    pdf.setFontSize(11); pdf.setFont('helvetica', 'bold');
    pdf.setTextColor(30, 41, 59);
    pdf.text('AI Classification', marginL, y);
    y += 6;
    ai.all_classes.forEach(cls => {
      const pct = (cls.probability * 100).toFixed(1);
      const isM = cls.label.toLowerCase().includes('murmur');
      pdf.setFontSize(9); pdf.setFont('helvetica', 'normal');
      pdf.setTextColor(71, 85, 105);
      pdf.text(`${cls.label}:`, marginL + 5, y + 4);
      pdf.setFont('helvetica', 'bold');
      pdf.text(`${pct}%`, marginL + 35, y + 4);
      // Bar background
      pdf.setFillColor(226, 232, 240);
      pdf.roundedRect(marginL + 52, y, contentW - 60, 6, 2, 2, 'F');
      // Bar fill
      const barW = Math.max(2, (cls.probability) * (contentW - 60));
      pdf.setFillColor(isM ? 239 : 34, isM ? 68 : 197, isM ? 68 : 94);
      pdf.roundedRect(marginL + 52, y, barW, 6, 2, 2, 'F');
      y += 12;
    });
    y += 4;

    // === FEATURE DETAILS ===
    pdf.setFontSize(11); pdf.setFont('helvetica', 'bold');
    pdf.setTextColor(30, 41, 59);
    pdf.text('Signal Analysis Features', marginL, y);
    y += 5;
    pdf.setFillColor(248, 250, 252);
    pdf.rect(marginL, y, contentW, 8, 'F');
    pdf.setDrawColor(226, 232, 240);
    pdf.rect(marginL, y, contentW, 8, 'S');
    pdf.setFontSize(8); pdf.setFont('helvetica', 'normal');
    pdf.setTextColor(71, 85, 105);
    pdf.text(ai.details || '', marginL + 4, y + 5.5);
    y += 16;

    // === DISCLAIMER ===
    pdf.setFillColor(255, 251, 235);
    pdf.roundedRect(marginL, y, contentW, 22, 2, 2, 'F');
    pdf.setDrawColor(251, 191, 36);
    pdf.roundedRect(marginL, y, contentW, 22, 2, 2, 'S');
    pdf.setFontSize(8); pdf.setFont('helvetica', 'bold');
    pdf.setTextColor(146, 64, 14);
    pdf.text('IMPORTANT NOTICE', marginL + 5, y + 6);
    pdf.setFont('helvetica', 'normal'); pdf.setFontSize(7.5);
    pdf.setTextColor(120, 53, 15);
    pdf.text('This is an AI-assisted screening tool for preliminary cardiac assessment. Results are NOT diagnostic.', marginL + 5, y + 12);
    pdf.text('All findings should be confirmed by a veterinary cardiologist via echocardiography.', marginL + 5, y + 17);
    y += 28;

    // === FOOTER ===
    pdf.setFontSize(7); pdf.setTextColor(148, 163, 184);
    pdf.text('Model: CardioScreen Logistic Regression Classifier · Trained on: VetCPD + Hannover Vet School (21 canine recordings)', marginL, H - 12);
    pdf.text(`Generated: ${now}`, W - marginR, H - 12, { align: 'right' });

    pdf.save(`screening_${patientData.dogId}_${Date.now()}.pdf`);
  };

  const resetApp = () => {
    stopRecording();
    if (audioUrl) URL.revokeObjectURL(audioUrl);
    setAppState('upload');
    setPatientData({ dogId: '', breed: '', age: '' });
    setAnalysisResult(null);
    setAudioBlob(null);
    setAudioUrl(null);
    setTrimWaveform(null);
    setTrimDuration(0);
    rawAudioBuffer.current = null;
  };

  return (
    <div className="app-container">
      {/* Sidebar */}
      {/* Mobile Header */}
      <header className="mobile-header">
        <div className="mobile-logo">
          <div style={{ background: 'var(--accent-cyan)', padding: '6px', borderRadius: '7px' }}><Heart color="white" size={18} /></div>
          CardioScreen <span className="text-gradient" style={{ marginLeft: 4 }}>AI</span>
        </div>
        <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
          <button className="btn-icon" onClick={toggleTheme} title={theme === 'dark' ? 'Light mode' : 'Dark mode'}>
            {theme === 'dark' ? <Sun size={18} /> : <Moon size={18} />}
          </button>
          <button className="btn-icon" onClick={() => setMobileNavOpen(o => !o)} title="Menu">
            {mobileNavOpen ? <X size={18} /> : <Menu size={18} />}
          </button>
        </div>
      </header>

      {/* Mobile nav overlay */}
      <div className={`mobile-nav-overlay ${mobileNavOpen ? 'open' : ''}`} onClick={closeMobileNav} />

      <aside className={`sidebar ${mobileNavOpen ? 'mobile-open' : ''}`}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '32px' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
            <div style={{ background: 'var(--accent-cyan)', padding: '8px', borderRadius: '8px' }}><Heart color="white" size={22} /></div>
            <h2 style={{ fontSize: '1.1rem', margin: 0 }}>CardioScreen <span className="text-gradient">AI</span></h2>
          </div>
          {/* Theme toggle (desktop) */}
          <button className="btn-icon" onClick={toggleTheme} title={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} style={{ display: 'flex' }}>
            {theme === 'dark' ? <Sun size={16} /> : <Moon size={16} />}
          </button>
        </div>

        <nav>
          <div className={`nav-item ${(appState === 'upload' || appState === 'recording') ? 'active' : ''}`}
            onClick={() => { if (appState !== 'analyzing') { resetApp(); closeMobileNav(); } }}>
            <Upload size={17} /><span>New Scan</span>
          </div>
          <div className={`nav-item ${appState === 'dashboard' ? 'active' : ''}`} onClick={closeMobileNav}>
            <Activity size={17} /><span>Analysis Result</span>
          </div>
        </nav>

        <div style={{ marginTop: 'auto', padding: '14px', background: 'var(--bg-input)', borderRadius: '10px', border: '1px solid var(--border-color)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '6px' }}>
            <div style={{ width: '8px', height: '8px', borderRadius: '50%', background: 'var(--success)', boxShadow: '0 0 8px var(--success)' }}></div>
            <span style={{ fontSize: '0.85rem', color: 'var(--text-secondary)' }}>AI Engine Active</span>
          </div>
          <div style={{ fontSize: '0.78rem', color: 'var(--text-muted)' }}>v1.0 · Thesis Edition</div>
        </div>
      </aside>

      {/* Main Content */}
      <main className="main-content">

        {/* VIEW: UPLOAD / RECORD */}
        {(appState === 'upload' || appState === 'recording') && (
          <div className="animate-fade-in" style={{ maxWidth: '800px', margin: '0 auto' }}>
            <div className="dashboard-header">
              <div>
                <h1 className="header-title">New Patient Scan</h1>
                <p className="header-subtitle">Capture phonocardiogram via stethoscope + microphone</p>
              </div>
            </div>

            <div className="glass-card" style={{ marginBottom: '20px' }}>
              <h3 style={{ marginBottom: '14px', fontSize: '1rem' }}>Patient Details</h3>
              <div className="patient-row" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '14px' }}>
                <div>
                  <label style={{ display: 'block', marginBottom: '6px', fontSize: '0.85rem', color: 'var(--text-secondary)' }}>Dog ID *</label>
                  <input type="text" value={patientData.dogId} onChange={e => setPatientData({ ...patientData, dogId: e.target.value })} placeholder="e.g. DOG-001" disabled={appState === 'recording'}
                    style={{ width: '100%', background: 'var(--bg-input)', border: '1px solid var(--border-color)', padding: '10px 12px', borderRadius: '8px', color: 'var(--text-primary)', fontSize: '0.9rem', outline: 'none' }} />
                </div>
                <div>
                  <label style={{ display: 'block', marginBottom: '6px', fontSize: '0.85rem', color: 'var(--text-secondary)' }}>Breed</label>
                  <input type="text" value={patientData.breed} onChange={e => setPatientData({ ...patientData, breed: e.target.value })} placeholder="e.g. German Shepherd" disabled={appState === 'recording'}
                    style={{ width: '100%', background: 'var(--bg-input)', border: '1px solid var(--border-color)', padding: '10px 12px', borderRadius: '8px', color: 'var(--text-primary)', fontSize: '0.9rem', outline: 'none' }} />
                </div>
                <div>
                  <label style={{ display: 'block', marginBottom: '6px', fontSize: '0.85rem', color: 'var(--text-secondary)' }}>Age (Years)</label>
                  <input type="number" value={patientData.age} onChange={e => setPatientData({ ...patientData, age: e.target.value })} placeholder="e.g. 7" disabled={appState === 'recording'}
                    style={{ width: '100%', background: 'var(--bg-input)', border: '1px solid var(--border-color)', padding: '10px 12px', borderRadius: '8px', color: 'var(--text-primary)', fontSize: '0.9rem', outline: 'none' }} />
                </div>
              </div>
            </div>

            {appState === 'upload' ? (
              <div className="upload-zones-row" style={{ display: 'flex', gap: '20px' }}>
                <div className="upload-zone" style={{ flex: 1 }} onClick={startRecording}>
                  <div style={{ background: 'rgba(59,130,246,0.12)', padding: '20px', borderRadius: '50%', boxShadow: '0 0 24px rgba(59,130,246,0.3)' }}>
                    <Mic size={40} color="var(--accent-blue)" />
                  </div>
                  <h3 style={{ fontSize: '1.1rem' }}>Start Live Recording</h3>
                  <p style={{ color: 'var(--text-secondary)', fontSize: '0.88rem' }}>Record from stethoscope microphone</p>
                </div>
                <div className="upload-zone" style={{ flex: 1 }} onClick={handleManualUpload}>
                  <div style={{ background: 'rgba(6,182,212,0.12)', padding: '20px', borderRadius: '50%', boxShadow: '0 0 24px rgba(6,182,212,0.25)' }}>
                    <FileAudio size={40} color="var(--accent-cyan)" />
                  </div>
                  <h3 style={{ fontSize: '1.1rem' }}>Upload Audio File</h3>
                  <p style={{ color: 'var(--text-secondary)', fontSize: '0.88rem' }}>WAV, MP3 or any audio format</p>
                </div>
              </div>
            ) : (
              <div className="glass-card" style={{ border: '2px solid var(--danger)', textAlign: 'center' }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
                    <div style={{ width: '12px', height: '12px', borderRadius: '50%', background: 'var(--danger)', animation: 'pulse-danger 1s infinite' }}></div>
                    <span style={{ color: 'var(--danger)', fontWeight: 600 }}>RECORDING</span>
                  </div>
                  <div style={{ fontFamily: 'monospace', fontSize: '1.5rem', fontWeight: 600 }}>
                    00:{recordingTime.toString().padStart(2, '0')}
                  </div>
                </div>
                <div style={{ width: '100%', height: '180px', background: 'rgba(0,0,0,0.5)', borderRadius: '8px', overflow: 'hidden', marginBottom: '24px', border: '1px solid rgba(255,255,255,0.05)' }}>
                  <canvas ref={canvasRef} width="800" height="180" style={{ width: '100%', height: '100%' }}></canvas>
                </div>
                <div style={{ display: 'flex', gap: '16px', justifyContent: 'center' }}>
                  <button className="btn-secondary" onClick={stopRecording}>
                    <AlertTriangle size={18} /> Cancel
                  </button>
                  <button className="btn-danger" onClick={handleFinishRecording}>
                    <Square size={18} fill="white" /> Stop & Analyze
                  </button>
                </div>
              </div>
            )}
          </div>
        )}

        {/* VIEW: TRIMMING */}
        {appState === 'trimming' && trimWaveform && (
          <div className="animate-fade-in" style={{ maxWidth: '900px', margin: '0 auto' }}>
            <div className="dashboard-header">
              <div>
                <h1 className="header-title">Trim Recording</h1>
                <p className="header-subtitle">Remove noise before the stethoscope was placed correctly</p>
              </div>
              <button className="btn-secondary" onClick={resetApp}>
                <RefreshCw size={16} /> Cancel
              </button>
            </div>
            <div className="glass-card">
              <div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '16px' }}>
                <div style={{ background: 'rgba(6,182,212,0.15)', padding: '8px', borderRadius: '8px' }}>
                  <Activity size={20} color="var(--accent-cyan)" />
                </div>
                <div>
                  <div style={{ fontWeight: 600, fontSize: '0.95rem' }}>Select Clean Section</div>
                  <div style={{ fontSize: '0.8rem', color: 'var(--text-secondary)' }}>
                    Full recording: {trimDuration.toFixed(1)}s &nbsp;·&nbsp; Drag handles to select just the heart sounds
                  </div>
                </div>
              </div>
              <AudioTrimmer
                waveform={trimWaveform}
                duration={trimDuration}
                onAnalyze={handleAnalyzeTrimmed}
                onSkip={handleSkipTrim}
              />
            </div>
          </div>
        )}

        {/* VIEW: ANALYZING */}
        {appState === 'analyzing' && (
          <div className="animate-fade-in" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
            <RefreshCw size={48} color="var(--accent-cyan)" style={{ animation: 'spin 2s linear infinite', marginBottom: '24px' }} />
            <style>{`@keyframes spin { 100% { transform: rotate(360deg); } }`}</style>
            <h2>Analyzing Heart Sound...</h2>
            <p style={{ color: 'var(--text-secondary)', marginTop: '8px', maxWidth: '400px', textAlign: 'center' }}>
              Running cardiac screening via pre-trained AI model on your local machine.
            </p>
          </div>
        )}

        {/* VIEW: DASHBOARD */}
        {appState === 'dashboard' && analysisResult && (
          <div className="animate-fade-in delay-100">
            <div className="dashboard-header">
              <div>
                <h1 className="header-title">Screening Result</h1>
                <p className="header-subtitle">Patient: {patientData.dogId} | Breed: {patientData.breed || 'N/A'} | Age: {patientData.age || 'N/A'}</p>
              </div>
              <div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap' }}>
                <button className="btn-secondary" onClick={downloadReport}>
                  <Download size={16} /> PDF Report
                </button>
                {audioBlob && (
                  <button className="btn-secondary" onClick={downloadAudio}>
                    <FileAudio size={16} /> Save Audio
                  </button>
                )}
                <button className="btn-secondary" onClick={resetApp}>
                  <RefreshCw size={16} /> New Scan
                </button>
              </div>
            </div>

            <div className="dashboard-grid">

              {/* Main Result Card */}
              <div className={`glass-card col-span-3 ${analysisResult.ai_classification.is_disease ? 'result-disease' : 'result-normal'}`}>

                {/* Header: Diagnosis + BPM */}
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '24px' }}>
                  <div>
                    <h3 style={{ color: 'var(--text-secondary)', fontSize: '0.9rem', marginBottom: '8px', textTransform: 'uppercase', letterSpacing: '1px' }}>
                      AI Cardiac Screening
                    </h3>
                    <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
                      {analysisResult.ai_classification.is_disease ? (
                        <AlertTriangle size={36} color="var(--danger)" />
                      ) : (
                        <CheckCircle size={36} color="var(--success)" />
                      )}
                      <h2 style={{ fontSize: '2.2rem', margin: 0, color: analysisResult.ai_classification.is_disease ? 'var(--danger)' : 'var(--success)' }}>
                        {analysisResult.clinical_summary}
                      </h2>
                    </div>
                  </div>

                  {/* BPM + Heartbeat Count */}
                  <div style={{ display: 'flex', gap: '16px' }}>
                    <div style={{ textAlign: 'center', background: 'rgba(0,0,0,0.2)', padding: '16px 24px', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.05)' }}>
                      <div style={{ fontSize: '3rem', fontWeight: 800, color: analysisResult.bpmColor, lineHeight: 1 }}>
                        {analysisResult.bpm}
                      </div>
                      <div style={{ fontSize: '0.9rem', color: 'var(--text-secondary)', marginTop: '4px' }}>BPM</div>
                      <div style={{ color: analysisResult.bpmColor, fontSize: '0.8rem', fontWeight: 600, marginTop: '4px', display: 'flex', alignItems: 'center', gap: '4px', justifyContent: 'center' }}>
                        <Activity size={12} /> {analysisResult.bpmStatus}
                      </div>
                    </div>
                    <div style={{ textAlign: 'center', background: 'rgba(0,0,0,0.2)', padding: '16px 24px', borderRadius: '12px', border: '1px solid rgba(255,255,255,0.05)' }}>
                      <div style={{ fontSize: '3rem', fontWeight: 800, color: 'var(--accent-cyan)', lineHeight: 1 }}>
                        {analysisResult.heartbeat_count}
                      </div>
                      <div style={{ fontSize: '0.9rem', color: 'var(--text-secondary)', marginTop: '4px' }}>Beats</div>
                      <div style={{ color: 'var(--text-secondary)', fontSize: '0.8rem', marginTop: '4px' }}>
                        in {analysisResult.duration_seconds}s
                      </div>
                    </div>
                  </div>
                </div>

                {/* Audio Player */}
                {audioUrl && (
                  <div style={{ marginBottom: '16px', background: 'rgba(0,0,0,0.25)', borderRadius: '12px', padding: '14px 18px', border: '1px solid rgba(255,255,255,0.05)', display: 'flex', alignItems: 'center', gap: '14px' }}>
                    <FileAudio size={20} color="var(--accent-cyan)" style={{ flexShrink: 0 }} />
                    <span style={{ fontSize: '0.85rem', color: 'var(--text-secondary)', flexShrink: 0 }}>Playback</span>
                    <audio controls src={audioUrl} ref={audioRef} style={{ flex: 1, height: '36px', borderRadius: '8px' }} />
                  </div>
                )}

                {/* Waveform with time axis + beat markers */}
                <div style={{ marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '16px' }}>
                  <span style={{ fontSize: '0.85rem', color: 'var(--text-secondary)', display: 'flex', alignItems: 'center', gap: '6px' }}>
                    <span style={{ display: 'inline-block', width: 10, height: 10, background: analysisResult.ai_classification.is_disease ? 'var(--danger)' : 'var(--accent-cyan)', transform: 'rotate(45deg)' }}></span>
                    Heartbeat peaks ({analysisResult.peak_times_seconds?.length ?? 0} detected)
                  </span>
                  <span style={{ fontSize: '0.85rem', color: 'var(--text-secondary)' }}>Duration: {analysisResult.duration_seconds}s</span>
                </div>
                <div style={{ width: '100%', height: '280px', background: 'rgba(0,0,0,0.35)', borderRadius: '12px', overflow: 'hidden', border: '1px solid rgba(255,255,255,0.05)' }}>
                  <WaveformCanvas
                    waveform={analysisResult.waveform}
                    peakVisIndices={analysisResult.peak_vis_indices}
                    peakTimesSec={analysisResult.peak_times_seconds}
                    duration={analysisResult.duration_seconds}
                    isDisease={analysisResult.ai_classification.is_disease}
                    canvasRefOut={waveformCanvasRef}
                    audioRef={audioRef}
                  />
                </div>

                {/* AI Probability Breakdown */}
                <div style={{ marginTop: '24px', background: 'rgba(0,0,0,0.2)', borderRadius: '12px', padding: '24px', border: '1px solid rgba(255,255,255,0.05)' }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
                    <div style={{ color: 'var(--text-secondary)', fontSize: '1rem', display: 'flex', alignItems: 'center', gap: '8px' }}>
                      <Cpu size={18} color="var(--accent-cyan)" /> AI Probability Breakdown
                    </div>
                    <div style={{ fontSize: '0.8rem', color: 'var(--text-secondary)', opacity: 0.7 }}>
                      CardioScreen · Logistic Regression · 21 recordings
                    </div>
                  </div>

                  {analysisResult.ai_classification.all_classes.map((cls, idx) => {
                    const pct = (cls.probability * 100).toFixed(1);
                    const isTop = cls.label === analysisResult.ai_classification.label;
                    const isMurmur = cls.label.toLowerCase().includes('murmur') || cls.label.toLowerCase().includes('abnormal');
                    const barColor = isMurmur ? 'var(--danger)' : 'var(--success)';

                    return (
                      <div key={idx} style={{ marginBottom: '16px' }}>
                        <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '6px' }}>
                          <span style={{ color: isTop ? 'white' : 'var(--text-secondary)', fontWeight: isTop ? 700 : 400, fontSize: '0.95rem' }}>
                            {cls.label} {isTop && '★'}
                          </span>
                          <span style={{ color: isTop ? 'white' : 'var(--text-secondary)', fontWeight: 600 }}>
                            {pct}%
                          </span>
                        </div>
                        <div className="confidence-bar-bg" style={{ height: '10px', borderRadius: '5px' }}>
                          <div className="confidence-bar-fill" style={{
                            borderRadius: '5px',
                            width: `${Math.max(2, pct)}%`,
                            background: isTop ? barColor : 'rgba(255,255,255,0.15)',
                            transition: 'width 1s ease'
                          }}></div>
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>

              {/* Canine Reference Table */}
              <div className="glass-card col-span-3" style={{ borderTop: '1px solid rgba(255,255,255,0.1)' }}>
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '32px' }}>
                  <div>
                    <h3 style={{ marginBottom: '16px', display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--accent-cyan)' }}>
                      <Activity size={18} /> Normal Heart Rate (Canine)
                    </h3>
                    <table style={{ width: '100%', fontSize: '0.85rem', borderCollapse: 'collapse', color: 'var(--text-secondary)' }}>
                      <thead>
                        <tr style={{ textAlign: 'left', borderBottom: '1px solid rgba(255,255,255,0.05)' }}>
                          <th style={{ padding: '8px 0' }}>Dog Size</th>
                          <th style={{ padding: '8px 0' }}>Normal Range</th>
                        </tr>
                      </thead>
                      <tbody>
                        <tr><td style={{ padding: '8px 0' }}>Large (60lb+)</td><td style={{ color: 'white' }}>60 – 100 BPM</td></tr>
                        <tr><td style={{ padding: '8px 0' }}>Medium (20–60lb)</td><td style={{ color: 'white' }}>80 – 120 BPM</td></tr>
                        <tr><td style={{ padding: '8px 0' }}>Small (&lt;20lb)</td><td style={{ color: 'white' }}>100 – 160 BPM</td></tr>
                        <tr><td style={{ padding: '8px 0' }}>Puppies</td><td style={{ color: 'white' }}>Up to 220 BPM</td></tr>
                      </tbody>
                    </table>
                  </div>
                  <div>
                    <h3 style={{ marginBottom: '16px', display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--accent-cyan)' }}>
                      <Heart size={18} /> Murmur Grading (Levine Scale)
                    </h3>
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px', fontSize: '0.8rem' }}>
                      <div style={{ background: 'rgba(255,255,255,0.02)', padding: '8px', borderRadius: '4px' }}>
                        <b style={{ color: 'white' }}>Grade I:</b> Very faint
                      </div>
                      <div style={{ background: 'rgba(255,255,255,0.02)', padding: '8px', borderRadius: '4px' }}>
                        <b style={{ color: 'white' }}>Grade II:</b> Soft, easily heard
                      </div>
                      <div style={{ background: 'rgba(255,255,255,0.02)', padding: '8px', borderRadius: '4px' }}>
                        <b style={{ color: 'white' }}>Grade III:</b> Intermediate
                      </div>
                      <div style={{ background: 'rgba(255,255,255,0.02)', padding: '8px', borderRadius: '4px' }}>
                        <b style={{ color: 'white' }}>Grade IV:</b> Loud, no thrill
                      </div>
                      <div style={{ background: 'rgba(255,255,255,0.02)', padding: '8px', borderRadius: '4px' }}>
                        <b style={{ color: 'white' }}>Grade V:</b> With palpable thrill
                      </div>
                      <div style={{ background: 'rgba(255,255,255,0.02)', padding: '8px', borderRadius: '4px' }}>
                        <b style={{ color: 'white' }}>Grade VI:</b> Heard without stethoscope
                      </div>
                    </div>
                  </div>
                </div>
              </div>

            </div>
          </div>
        )}

      </main>
    </div>
  );
}

export default App;
