'use client';

import { useState, useRef, useEffect, useCallback } from 'react';

const API_URL = process.env.NEXT_PUBLIC_API_URL || '';
const DB_NAME = 'bird-capture-queue';
const STORE_NAME = 'pending';
const MAX_IMAGE_PX = 1568; // Claude vision optimal max dimension

// IndexedDB queue
async function openDB(): Promise<IDBDatabase> {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(DB_NAME, 1);
    req.onupgradeneeded = () => req.result.createObjectStore(STORE_NAME, { keyPath: 'id' });
    req.onsuccess = () => resolve(req.result);
    req.onerror = () => reject(req.error);
  });
}

async function queueCapture(formData: FormData) {
  const db = await openDB();
  const id = Date.now().toString();
  const audio = formData.get('audio') as Blob | null;
  const image = formData.get('image') as Blob | null;
  return new Promise<void>((resolve, reject) => {
    const tx = db.transaction(STORE_NAME, 'readwrite');
    tx.objectStore(STORE_NAME).put({
      id,
      audio: audio || null,
      image: image || null,
      timestamp: new Date().toISOString(),
    });
    tx.oncomplete = () => resolve();
    tx.onerror = () => reject(tx.error);
  });
}

async function getPendingCaptures(): Promise<any[]> {
  const db = await openDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(STORE_NAME, 'readonly');
    const req = tx.objectStore(STORE_NAME).getAll();
    req.onsuccess = () => resolve(req.result);
    req.onerror = () => reject(req.error);
  });
}

async function removeCapture(id: string) {
  const db = await openDB();
  return new Promise<void>((resolve, reject) => {
    const tx = db.transaction(STORE_NAME, 'readwrite');
    tx.objectStore(STORE_NAME).delete(id);
    tx.oncomplete = () => resolve();
    tx.onerror = () => reject(tx.error);
  });
}

// Resize image client-side before upload
async function resizeImage(file: File): Promise<Blob> {
  return new Promise((resolve) => {
    const img = new Image();
    const url = URL.createObjectURL(file);
    img.onload = () => {
      URL.revokeObjectURL(url);
      const { width, height } = img;
      const maxDim = MAX_IMAGE_PX;
      let w = width, h = height;
      if (w > maxDim || h > maxDim) {
        if (w > h) { h = Math.round(h * maxDim / w); w = maxDim; }
        else { w = Math.round(w * maxDim / h); h = maxDim; }
      }
      const canvas = document.createElement('canvas');
      canvas.width = w;
      canvas.height = h;
      const ctx = canvas.getContext('2d')!;
      ctx.drawImage(img, 0, 0, w, h);
      canvas.toBlob((blob) => resolve(blob!), 'image/jpeg', 0.88);
    };
    img.src = url;
  });
}

async function submitCapture(audio: Blob | null, image: Blob | null): Promise<boolean> {
  try {
    const form = new FormData();
    if (audio) form.append('audio', audio, 'capture.webm');
    if (image) form.append('image', image, 'capture.jpg');
    const res = await fetch(`${API_URL}/api/capture`, { method: 'POST', body: form });
    return res.ok;
  } catch {
    return false;
  }
}

type CaptureMode = 'idle' | 'image-selected' | 'recording' | 'submitting' | 'saved' | 'queued' | 'error';

export default function CapturePage() {
  const [mode, setMode] = useState<CaptureMode>('idle');
  const [imagePreview, setImagePreview] = useState<string | null>(null);
  const [imageBlob, setImageBlob] = useState<Blob | null>(null);
  const [countdown, setCountdown] = useState(0);
  const [pendingCount, setPendingCount] = useState(0);
  const [recentCaptures, setRecentCaptures] = useState<{name: string}[]>([]);

  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<Blob[]>([]);
  const streamRef = useRef<MediaStream | null>(null);
  const wakeLockRef = useRef<any>(null);
  const countdownRef = useRef<any>(null);
  const mimeTypeRef = useRef('audio/webm');
  const fileInputRef = useRef<HTMLInputElement>(null);
  const MAX_SECONDS = 120; // shorter for annotation — 2 min max

  useEffect(() => {
    loadRecentCaptures();
    checkPending();
    window.addEventListener('focus', retryQueue);
    window.addEventListener('online', retryQueue);
    return () => {
      window.removeEventListener('focus', retryQueue);
      window.removeEventListener('online', retryQueue);
    };
  }, []);

  async function loadRecentCaptures() {
    try {
      const res = await fetch(`${API_URL}/api/captures`);
      if (res.ok) {
        const data = await res.json();
        setRecentCaptures(data.captures || []);
      }
    } catch {}
  }

  async function checkPending() {
    try {
      const p = await getPendingCaptures();
      setPendingCount(p.length);
    } catch {}
  }

  async function retryQueue() {
    try {
      const pending = await getPendingCaptures();
      for (const item of pending) {
        const ok = await submitCapture(item.audio, item.image);
        if (ok) await removeCapture(item.id);
      }
      const remaining = await getPendingCaptures();
      setPendingCount(remaining.length);
      if (remaining.length < pending.length) loadRecentCaptures();
    } catch {}
  }

  // ── Image selection ────────────────────────────────────────────────────────

  function handleCameraClick() {
    fileInputRef.current?.click();
  }

  async function handleImageSelected(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) return;
    const resized = await resizeImage(file);
    setImageBlob(resized);
    const preview = URL.createObjectURL(resized);
    setImagePreview(preview);
    setMode('image-selected');
    // Reset input so same file can be reselected
    e.target.value = '';
  }

  function clearImage() {
    if (imagePreview) URL.revokeObjectURL(imagePreview);
    setImagePreview(null);
    setImageBlob(null);
    setMode('idle');
    stopRecording();
  }

  // ── Voice recording ────────────────────────────────────────────────────────

  async function acquireWakeLock() {
    try {
      if ('wakeLock' in navigator) {
        wakeLockRef.current = await (navigator as any).wakeLock.request('screen');
      }
    } catch {}
  }

  function releaseWakeLock() {
    wakeLockRef.current?.release();
    wakeLockRef.current = null;
  }

  async function startRecording() {
    try {
      if (!streamRef.current || streamRef.current.getTracks().every(t => t.readyState === 'ended')) {
        streamRef.current = await navigator.mediaDevices.getUserMedia({ audio: true });
      }
      const mimeType = MediaRecorder.isTypeSupported('audio/webm') ? 'audio/webm'
        : MediaRecorder.isTypeSupported('audio/mp4') ? 'audio/mp4' : 'audio/ogg';
      mimeTypeRef.current = mimeType;
      chunksRef.current = [];
      const mr = new MediaRecorder(streamRef.current, { mimeType });
      mr.ondataavailable = e => { if (e.data.size > 0) chunksRef.current.push(e.data); };
      mr.onstop = async () => {
        streamRef.current?.getTracks().forEach(t => t.stop());
        streamRef.current = null;
        if (chunksRef.current.length === 0) {
          // No audio recorded — submit image only
          await submitFinal(null);
          return;
        }
        const audioBlob = new Blob(chunksRef.current, { type: mimeTypeRef.current });
        await submitFinal(audioBlob);
      };
      mr.start(1000);
      mediaRecorderRef.current = mr;
      setMode('recording');
      setCountdown(MAX_SECONDS);
      await acquireWakeLock();
      countdownRef.current = setInterval(() => {
        setCountdown(prev => {
          if (prev <= 1) { stopRecording(); return 0; }
          return prev - 1;
        });
      }, 1000);
    } catch {
      setMode('error');
      setTimeout(() => setMode(imageBlob ? 'image-selected' : 'idle'), 3000);
    }
  }

  function stopRecording() {
    if (countdownRef.current) { clearInterval(countdownRef.current); countdownRef.current = null; }
    releaseWakeLock();
    if (mediaRecorderRef.current?.state === 'recording') {
      mediaRecorderRef.current.stop();
    }
  }

  // ── Submission ─────────────────────────────────────────────────────────────

  async function submitFinal(audioBlob: Blob | null) {
    setMode('submitting');
    const ok = await submitCapture(audioBlob, imageBlob);
    if (ok) {
      setMode('saved');
      if (imagePreview) URL.revokeObjectURL(imagePreview);
      setImagePreview(null);
      setImageBlob(null);
      await loadRecentCaptures();
      setTimeout(() => setMode('idle'), 3000);
    } else {
      try {
        const form = new FormData();
        if (audioBlob) form.append('audio', audioBlob, 'capture.webm');
        if (imageBlob) form.append('image', imageBlob, 'capture.jpg');
        await queueCapture(form);
        await checkPending();
        setMode('queued');
      } catch {
        setMode('error');
      }
      if (imagePreview) URL.revokeObjectURL(imagePreview);
      setImagePreview(null);
      setImageBlob(null);
      setTimeout(() => setMode('idle'), 4000);
    }
  }

  async function submitImageOnly() {
    await submitFinal(null);
  }

  // ── Tap handler for voice button ───────────────────────────────────────────

  function handleVoiceTap() {
    if (mode === 'recording') stopRecording();
    else if (mode === 'image-selected') startRecording();
    else if (mode === 'idle') startRecording(); // voice-only capture
  }

  const isRecording = mode === 'recording';
  const isBusy = mode === 'submitting';
  const hasImage = imageBlob !== null;

  return (
    <div style={{
      minHeight: '100dvh',
      background: 'var(--bg)',
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      justifyContent: 'space-between',
      paddingTop: 'max(48px, env(safe-area-inset-top))',
      paddingBottom: 'max(32px, env(safe-area-inset-bottom))',
      paddingLeft: 'max(24px, env(safe-area-inset-left))',
      paddingRight: 'max(24px, env(safe-area-inset-right))',
      fontFamily: 'var(--font-mono)',
    }}>

      {/* Header */}
      <div style={{ textAlign: 'center' }}>
        <p style={{ fontSize: '10px', letterSpacing: '0.15em', color: 'var(--text3)', textTransform: 'uppercase', margin: 0 }}>
          Bird — field recorder
        </p>
        {pendingCount > 0 && (
          <p style={{ fontSize: '9px', color: '#c8821a', letterSpacing: '0.1em', margin: '4px 0 0', textTransform: 'uppercase' }}>
            {pendingCount} capture{pendingCount > 1 ? 's' : ''} queued
          </p>
        )}
      </div>

      {/* Main area */}
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '28px', width: '100%', maxWidth: '320px' }}>

        {/* Image preview */}
        {imagePreview && (
          <div style={{ position: 'relative', width: '100%' }}>
            <img
              src={imagePreview}
              alt="capture preview"
              style={{
                width: '100%',
                maxHeight: '240px',
                objectFit: 'cover',
                borderRadius: '12px',
                border: '1px solid var(--border)',
                display: 'block',
              }}
            />
            <button
              onClick={clearImage}
              style={{
                position: 'absolute', top: '8px', right: '8px',
                background: 'rgba(0,0,0,0.6)', border: 'none',
                borderRadius: '50%', width: '28px', height: '28px',
                color: '#fff', cursor: 'pointer', fontSize: '16px',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}
            >×</button>
          </div>
        )}

        {/* Waveform — shows during recording */}
        {isRecording && (
          <div style={{ display: 'flex', alignItems: 'center', gap: '3px', height: '32px' }}>
            {[4,8,16,6,24,10,32,14,20,8,12,28,6,18,4].map((h, i) => (
              <div key={i} style={{
                width: '2px', height: `${h}px`, background: 'var(--accent)', borderRadius: '1px',
                animation: `wave ${0.8 + (i % 4) * 0.2}s ease-in-out infinite alternate`,
              }} />
            ))}
          </div>
        )}

        {/* Capture buttons row */}
        <div style={{ display: 'flex', gap: '24px', alignItems: 'center', justifyContent: 'center' }}>

          {/* Camera button — always visible, opens image picker */}
          <button
            onClick={handleCameraClick}
            disabled={isBusy || isRecording}
            style={{
              width: '72px', height: '72px', borderRadius: '50%',
              border: `1.5px solid ${hasImage ? 'var(--accent)' : 'var(--border2)'}`,
              background: hasImage ? 'var(--accent-light)' : 'var(--bg2)',
              cursor: isBusy || isRecording ? 'not-allowed' : 'pointer',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              transition: 'all 0.2s', touchAction: 'manipulation',
              opacity: isBusy || isRecording ? 0.5 : 1,
            }}
            aria-label="Take photo or choose image"
          >
            <svg width="24" height="24" viewBox="0 0 24 24" fill="none"
              stroke={hasImage ? 'var(--accent)' : 'var(--text3)'} strokeWidth="1.5">
              <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
              <circle cx="12" cy="13" r="4"/>
            </svg>
          </button>

          {/* Mic / submit button — large center */}
          <button
            onPointerUp={handleVoiceTap}
            disabled={isBusy}
            style={{
              width: '120px', height: '120px', borderRadius: '50%',
              border: `1.5px solid ${isRecording ? '#a32d2d' : 'var(--accent)'}`,
              background: isRecording ? 'rgba(163,45,45,0.08)' : 'var(--bg2)',
              cursor: isBusy ? 'not-allowed' : 'pointer',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              transition: 'all 0.3s', touchAction: 'manipulation',
              animation: isBusy ? 'none' : isRecording ? 'recordPulse 1.5s ease-in-out infinite' : 'idlePulse 3s ease-in-out infinite',
            }}
            aria-label={isRecording ? 'Stop recording' : 'Record voice annotation'}
          >
            {isBusy ? (
              <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" style={{ color: 'var(--accent)' }}>
                <circle cx="12" cy="12" r="3" opacity="0.6">
                  <animate attributeName="opacity" values="0.6;1;0.6" dur="1s" repeatCount="indefinite"/>
                </circle>
              </svg>
            ) : isRecording ? (
              <div style={{ width: '20px', height: '20px', background: '#a32d2d', borderRadius: '4px' }} />
            ) : (
              <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" strokeWidth="1.5">
                <path d="M12 1a4 4 0 0 1 4 4v6a4 4 0 0 1-8 0V5a4 4 0 0 1 4-4z"/>
                <path d="M5 11a7 7 0 0 0 14 0"/>
                <line x1="12" y1="18" x2="12" y2="22"/>
                <line x1="8" y1="22" x2="16" y2="22"/>
              </svg>
            )}
          </button>

          {/* Submit image-only button — visible only when image selected and not recording */}
          {hasImage && !isRecording && !isBusy ? (
            <button
              onClick={submitImageOnly}
              style={{
                width: '72px', height: '72px', borderRadius: '50%',
                border: '1.5px solid var(--accent)',
                background: 'var(--accent-light)',
                cursor: 'pointer',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                transition: 'all 0.2s', touchAction: 'manipulation',
              }}
              aria-label="Save image without annotation"
            >
              <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" strokeWidth="2">
                <polyline points="20 6 9 17 4 12"/>
              </svg>
            </button>
          ) : (
            <div style={{ width: '72px', height: '72px' }} />
          )}
        </div>

        {/* Recording progress */}
        {isRecording && (
          <div style={{ width: '100%' }}>
            <div style={{ width: '100%', height: '2px', background: 'var(--border)', borderRadius: '1px', overflow: 'hidden', marginBottom: '6px' }}>
              <div style={{
                height: '100%',
                width: `${((MAX_SECONDS - countdown) / MAX_SECONDS) * 100}%`,
                background: countdown <= 15 ? '#a32d2d' : 'var(--accent)',
                borderRadius: '1px', transition: 'width 1s linear',
              }} />
            </div>
            <p style={{ fontSize: '10px', color: 'var(--text3)', margin: 0, textAlign: 'center' }}>
              {(() => {
                const rm = Math.floor(countdown / 60);
                const rs = countdown % 60;
                return `${rm}:${rs.toString().padStart(2,'0')} left`;
              })()}
            </p>
          </div>
        )}

        {/* Status */}
        <div style={{ textAlign: 'center', minHeight: '20px' }}>
          {mode === 'idle' && (
            <p style={{ fontSize: '10px', color: 'var(--text3)', letterSpacing: '0.12em', textTransform: 'uppercase', margin: 0 }}>
              tap camera or mic
            </p>
          )}
          {mode === 'image-selected' && (
            <p style={{ fontSize: '10px', color: 'var(--text3)', letterSpacing: '0.10em', textTransform: 'uppercase', margin: 0 }}>
              annotate with voice or save now
            </p>
          )}
          {mode === 'recording' && (
            <p style={{ fontSize: '10px', color: '#a32d2d', letterSpacing: '0.12em', textTransform: 'uppercase', margin: 0 }}>
              recording annotation
            </p>
          )}
          {mode === 'submitting' && (
            <p style={{ fontSize: '10px', color: 'var(--text3)', letterSpacing: '0.12em', textTransform: 'uppercase', margin: 0 }}>
              {hasImage ? 'processing image...' : 'transcribing...'}
            </p>
          )}
          {mode === 'saved' && (
            <p style={{ fontSize: '10px', color: 'var(--accent)', letterSpacing: '0.12em', textTransform: 'uppercase', margin: 0 }}>
              saved ✓
            </p>
          )}
          {mode === 'queued' && (
            <p style={{ fontSize: '10px', color: '#c8821a', letterSpacing: '0.12em', textTransform: 'uppercase', margin: 0 }}>
              queued — will sync when online
            </p>
          )}
          {mode === 'error' && (
            <p style={{ fontSize: '10px', color: '#a32d2d', letterSpacing: '0.12em', textTransform: 'uppercase', margin: 0 }}>
              error — try again
            </p>
          )}
        </div>
      </div>

      {/* Recent captures */}
      <div style={{ width: '100%', maxWidth: '320px' }}>
        <p style={{ fontSize: '9px', color: 'var(--text3)', letterSpacing: '0.12em', textTransform: 'uppercase', margin: '0 0 8px' }}>
          recent captures
        </p>
        {recentCaptures.length === 0 ? (
          <p style={{ fontSize: '10px', color: 'var(--text3)', margin: 0, opacity: 0.5 }}>none yet</p>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: '5px' }}>
            {recentCaptures.slice(0, 4).map((c, i) => (
              <div key={i} style={{
                display: 'flex', alignItems: 'center', gap: '8px', padding: '6px 10px',
                background: 'var(--bg2)', borderRadius: '6px', border: '1px solid var(--border)',
              }}>
                <div style={{
                  width: '6px', height: '6px', borderRadius: '50%', flexShrink: 0,
                  background: c.name.includes('image') ? '#c8821a' : 'var(--accent)',
                }} />
                <span style={{ fontSize: '10px', color: 'var(--text2)', flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                  {c.name}
                </span>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Hidden file input */}
      <input
        ref={fileInputRef}
        type="file"
        accept="image/*"
        capture="environment"
        onChange={handleImageSelected}
        style={{ display: 'none' }}
      />

      <style>{`
        @keyframes idlePulse {
          0%, 100% { box-shadow: 0 0 0 0 rgba(45,158,107,0); }
          50% { box-shadow: 0 0 0 12px rgba(45,158,107,0.06); }
        }
        @keyframes recordPulse {
          0%, 100% { box-shadow: 0 0 0 0 rgba(163,45,45,0); }
          50% { box-shadow: 0 0 0 16px rgba(163,45,45,0.08); }
        }
        @keyframes wave {
          from { transform: scaleY(0.4); }
          to { transform: scaleY(1.4); }
        }
      `}</style>
    </div>
  );
}
