import { useState, useRef, useEffect } from 'react';
import type { DragEvent, ChangeEvent } from 'react';
import { PageParseAPI, INDIAN_LANGUAGES } from '../services/api';
import type { ProcessingJob } from '../services/api';
import {
  UploadCloud, FileText, CheckCircle2, AlertCircle, Mic, Square, Camera, Files
} from 'lucide-react';

interface FileUploaderProps {
  onJobStarted: () => void;
  onJobFinished: () => void;
  isAirgapped: boolean;
}

export const FileUploader = ({ onJobStarted, onJobFinished, isAirgapped }: FileUploaderProps) => {
  const [isDragActive, setIsDragActive] = useState(false);
  const [currentJob, setCurrentJob] = useState<ProcessingJob | null>(null);
  const [activeJobs, setActiveJobs] = useState<ProcessingJob[]>([]);
  const [filePreview, setFilePreview] = useState<string | null>(null);
  const [selectedLanguage, setSelectedLanguage] = useState('English');
  const [schemaType, setSchemaType] = useState('auto');
  const [isRecording, setIsRecording] = useState(false);
  const [recordingDuration, setRecordingDuration] = useState(0);
  const [imageToConfigure, setImageToConfigure] = useState<File | null>(null);
  const [brightness, setBrightness] = useState(100);
  const [contrast, setContrast] = useState(100);
  const [binarize, setBinarize] = useState(false);
  const [threshold, setThreshold] = useState(128);
  const [rotation, setRotation] = useState(0);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const batchInputRef = useRef<HTMLInputElement>(null);
  const cameraInputRef = useRef<HTMLInputElement>(null);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const audioChunksRef = useRef<Blob[]>([]);
  const timerRef = useRef<any>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    if (!imageToConfigure || !canvasRef.current) return;
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;
    const img = new Image();
    img.src = URL.createObjectURL(imageToConfigure);
    img.onload = () => {
      const is90 = Math.abs(rotation % 180) === 90;
      canvas.width = is90 ? img.height : img.width;
      canvas.height = is90 ? img.width : img.height;
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.save();
      ctx.translate(canvas.width / 2, canvas.height / 2);
      ctx.rotate((rotation * Math.PI) / 180);
      ctx.drawImage(img, -img.width / 2, -img.height / 2);
      ctx.restore();
      let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      let data = imgData.data;
      const bFactor = brightness / 100;
      const cFactor = contrast / 100;
      for (let i = 0; i < data.length; i += 4) {
        for (let c = 0; c < 3; c++) {
          let val = data[i + c];
          val = val * bFactor;
          val = ((val - 128) * cFactor) + 128;
          data[i + c] = Math.min(255, Math.max(0, val));
        }
        if (binarize) {
          const gray = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
          const binVal = gray < threshold ? 0 : 255;
          data[i] = binVal; data[i + 1] = binVal; data[i + 2] = binVal;
        }
      }
      ctx.putImageData(imgData, 0, 0);
    };
  }, [imageToConfigure, brightness, contrast, binarize, threshold, rotation]);

  const startRecording = async (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    audioChunksRef.current = [];
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const recorder = new MediaRecorder(stream);
      mediaRecorderRef.current = recorder;
      recorder.ondataavailable = (event) => { if (event.data.size > 0) audioChunksRef.current.push(event.data); };
      recorder.onstop = () => {
        const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/wav' });
        const file = new File([audioBlob], `recorded_voice_${Date.now()}.wav`, { type: 'audio/wav' });
        processSelectedFile(file);
        stream.getTracks().forEach(track => track.stop());
      };
      recorder.start();
      setIsRecording(true);
      setRecordingDuration(0);
      timerRef.current = setInterval(() => setRecordingDuration(prev => prev + 1), 1000);
    } catch (err) {
      alert("Microphone access error: " + err);
    }
  };

  const stopRecording = (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (mediaRecorderRef.current && isRecording) {
      mediaRecorderRef.current.stop();
      setIsRecording(false);
      if (timerRef.current) clearInterval(timerRef.current);
    }
  };

  const takePhoto = async (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } });
      const track = stream.getVideoTracks()[0];
      const imageCapture = new (window as any).ImageCapture(track);
      const photoBlob = await imageCapture.takePhoto();
      track.stop();
      const file = new File([photoBlob], `camera_${Date.now()}.jpg`, { type: 'image/jpeg' });
      processSelectedFile(file);
    } catch (err) {
      cameraInputRef.current?.click();
    }
  };

  const uploadProcessedFile = async (file: File) => {
    try {
      const job = await PageParseAPI.uploadPage(file, selectedLanguage, schemaType, (updatedJob) => {
        setCurrentJob(updatedJob);
        if (updatedJob.status === 'saved' || updatedJob.status === 'failed') {
          onJobFinished();
          setTimeout(() => { setCurrentJob(null); setFilePreview(null); }, 3000);
        }
      });
      setCurrentJob(job);
      onJobStarted();
    } catch (err: any) {
      console.error(err);
      setCurrentJob({ id: 'err', filename: file.name, status: 'failed', progress: 0, error: err.message || 'Processing failed' });
      onJobFinished();
    }
  };

  const uploadBatchFiles = async (files: FileList) => {
    onJobStarted();
    const jobs: ProcessingJob[] = [];
    for (const file of Array.from(files)) {
      jobs.push({ id: Math.random().toString(36).substring(2, 9), filename: file.name, status: 'queued', progress: 0 });
    }
    setActiveJobs(jobs);

    for (let i = 0; i < files.length; i++) {
      const file = files[i];
      try {
        await PageParseAPI.uploadPage(file, selectedLanguage, schemaType, (updatedJob) => {
          setActiveJobs(prev => prev.map(j => j.id === updatedJob.id ? updatedJob : j));
        });
      } catch (err) {
        console.error(`Failed to upload ${file.name}:`, err);
      }
    }
    onJobFinished();
    setTimeout(() => setActiveJobs([]), 5000);
  };

  const confirmAndProcess = () => {
    const canvas = canvasRef.current;
    if (!canvas || !imageToConfigure) return;
    canvas.toBlob((blob) => {
      if (blob) {
        const processedFile = new File([blob], imageToConfigure.name, { type: 'image/jpeg' });
        setImageToConfigure(null);
        uploadProcessedFile(processedFile);
      }
    }, 'image/jpeg', 0.9);
  };

  const handleDrag = (e: DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (e.type === "dragenter" || e.type === "dragover") setIsDragActive(true);
    else if (e.type === "dragleave") setIsDragActive(false);
  };

  const processSelectedFile = async (file: File) => {
    if (!file) return;
    if (file.type.startsWith('image/')) {
      setImageToConfigure(file);
      const reader = new FileReader();
      reader.onloadend = () => setFilePreview(reader.result as string);
      reader.readAsDataURL(file);
    } else {
      setFilePreview(null);
      uploadProcessedFile(file);
    }
  };

  const handleDrop = (e: DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragActive(false);
    if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
      if (e.dataTransfer.files.length > 1) {
        uploadBatchFiles(e.dataTransfer.files);
      } else {
        processSelectedFile(e.dataTransfer.files[0]);
      }
    }
  };

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files[0]) processSelectedFile(e.target.files[0]);
  };

  const handleBatchChange = (e: ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files.length > 0) {
      uploadBatchFiles(e.target.files);
    }
  };

  const handleCameraCapture = (e: ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files[0]) processSelectedFile(e.target.files[0]);
  };

  const getStatusText = (status: string) => {
    const map: Record<string, string> = {
      queued: 'Queued',
      preprocessing: 'OpenCV Preprocessing',
      ocr: 'OCR Inference (CPU)',
      extracting: 'SLM + GBNF Structuring',
      saved: 'Saved to SQLite',
      failed: 'Failed',
    };
    return map[status] || status;
  };

  const schemaOptions = [
    { value: 'auto', label: 'Auto-Detect' },
    { value: 'todo', label: 'Planner / To-Do' },
    { value: 'meeting', label: 'Meeting Minutes' },
    { value: 'recipe', label: 'Recipe Card' },
    { value: 'survey', label: 'Survey Form' },
    { value: 'notes', label: 'General Notes' },
  ];

  return (
    <div className="section">
      <div className="section-header">
        <h3><UploadCloud size={16} className="text-secondary" /> Local Ingestion</h3>
        {!currentJob && activeJobs.length === 0 && (
          <div className="flex gap-3 items-center">
            <select value={schemaType} onChange={e => setSchemaType(e.target.value)} className="select">
              {schemaOptions.map(opt => <option key={opt.value} value={opt.value}>{opt.label}</option>)}
            </select>
            <select value={selectedLanguage} onChange={e => setSelectedLanguage(e.target.value)} className="select">
              {INDIAN_LANGUAGES.map(lang => <option key={lang} value={lang}>{lang}</option>)}
            </select>
          </div>
        )}
      </div>

      <div className="section-body">
        <input ref={fileInputRef} type="file" className="hidden-file-input" onChange={handleChange} accept="image/png, image/jpeg, image/jpg, application/pdf, audio/*, video/*, text/*" style={{ display: 'none' }} />
        <input ref={batchInputRef} type="file" className="hidden-file-input" multiple onChange={handleBatchChange} accept="image/*,application/pdf,audio/*,video/*" style={{ display: 'none' }} />
        <input ref={cameraInputRef} type="file" accept="image/*" capture="environment" onChange={handleCameraCapture} style={{ display: 'none' }} />

        {activeJobs.length > 0 ? (
          <div className="flex flex-col gap-3">
            <div className="text-xs font-semibold text-tertiary mb-2">Batch Upload ({activeJobs.length} files)</div>
            {activeJobs.map(job => (
              <div key={job.id} className="flex items-center gap-3" style={{ padding: '8px 12px', background: 'var(--bg-elevated)', borderRadius: 'var(--radius-sm)' }}>
                <FileText size={16} className="text-tertiary" />
                <span className="text-sm flex-1">{job.filename}</span>
                <span className="text-xs text-tertiary">{getStatusText(job.status)}</span>
                {job.status === 'saved' && <CheckCircle2 size={14} style={{ color: 'var(--success)' }} />}
                {job.status === 'failed' && <AlertCircle size={14} style={{ color: 'var(--danger)' }} />}
              </div>
            ))}
          </div>
        ) : !currentJob ? (
          imageToConfigure ? (
            <div className="flex flex-col gap-4" style={{ padding: 16, background: 'var(--bg-elevated)', borderRadius: 'var(--radius-md)' }}>
              <h4 className="font-semibold text-sm text-secondary" style={{ margin: 0 }}>Adjust Handwritten Sheet</h4>
              <div style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr', gap: 16 }}>
                <div style={{ background: 'var(--bg-base)', border: '1px solid var(--border)', borderRadius: 'var(--radius-sm)', padding: 4, maxHeight: 300, display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
                  <canvas ref={canvasRef} style={{ maxWidth: '100%', maxHeight: 280, objectFit: 'contain', borderRadius: 4 }} />
                </div>
                <div className="flex flex-col gap-3 text-sm">
                  <div>
                    <div className="flex justify-between mb-3"><span>Brightness: {brightness}%</span></div>
                    <input type="range" min="50" max="150" value={brightness} onChange={e => setBrightness(Number(e.target.value))} style={{ width: '100%' }} />
                  </div>
                  <div>
                    <div className="flex justify-between mb-3"><span>Contrast: {contrast}%</span></div>
                    <input type="range" min="50" max="150" value={contrast} onChange={e => setContrast(Number(e.target.value))} style={{ width: '100%' }} />
                  </div>
                  <div>
                    <div className="flex justify-between mb-3"><span>Rotation: {rotation}°</span></div>
                    <input type="range" min="-180" max="180" value={rotation} onChange={e => setRotation(Number(e.target.value))} style={{ width: '100%' }} />
                  </div>
                  <label className="flex items-center gap-2" style={{ cursor: 'pointer' }} onClick={e => e.stopPropagation()}>
                    <input type="checkbox" checked={binarize} onChange={e => setBinarize(e.target.checked)} />
                    <span>Binarize Image</span>
                  </label>
                  {binarize && (
                    <div>
                      <div className="flex justify-between mb-3"><span>Threshold: {threshold}</span></div>
                      <input type="range" min="0" max="255" value={threshold} onChange={e => setThreshold(Number(e.target.value))} style={{ width: '100%' }} />
                    </div>
                  )}
                  <div className="flex gap-3 mt-2" onClick={e => e.stopPropagation()}>
                    <button className="btn btn-primary" onClick={confirmAndProcess} style={{ flex: 1, justifyContent: 'center' }}>Confirm & Process</button>
                    <button className="btn" onClick={() => setImageToConfigure(null)} style={{ flex: 1, justifyContent: 'center' }}>Cancel</button>
                  </div>
                </div>
              </div>
            </div>
          ) : (
            <div
              className={`dropzone ${isDragActive ? 'drag-over' : ''}`}
              onDragEnter={handleDrag} onDragOver={handleDrag}
              onDragLeave={handleDrag} onDrop={handleDrop}
              onClick={() => fileInputRef.current?.click()}
            >
              <UploadCloud className="dropzone-icon" />
              <div className="dropzone-title">Drop files here</div>
              <div className="dropzone-subtitle">Images · Audio · Video · PDF · DOCX · TXT · CSV</div>
              <div className="dropzone-actions" onClick={e => e.stopPropagation()}>
                <button className="btn btn-primary" onClick={(e) => { e.preventDefault(); fileInputRef.current?.click(); }}>Browse Files</button>
                <button className="btn" onClick={(e) => { e.preventDefault(); batchInputRef.current?.click(); }}><Files size={14} /> Batch</button>
                <button className="btn" onClick={takePhoto}><Camera size={14} /> Camera</button>
                {!isRecording ? (
                  <button className="btn" onClick={startRecording}><Mic size={14} /> Record</button>
                ) : (
                  <button className="btn" onClick={stopRecording} style={{ borderColor: 'var(--danger)', color: 'var(--danger)' }}>
                    <Square size={14} /> Stop ({Math.floor(recordingDuration / 60)}:{(recordingDuration % 60).toString().padStart(2, '0')})
                  </button>
                )}
              </div>
              {isAirgapped && <div className="text-xs text-tertiary" style={{ marginTop: 4 }}>Air-gap mode active — no network calls</div>}
            </div>
          )
        ) : (
          <div className="upload-progress">
            <div className="flex gap-3 items-center mb-3">
              {filePreview ? <img src={filePreview} alt="" style={{ width: 40, height: 40, borderRadius: 4, objectFit: 'cover', border: '1px solid var(--border)' }} />
                : <FileText size={32} className="text-tertiary" />}
              <div>
                <div className="font-semibold text-sm">{currentJob.filename}</div>
                <div className="text-xs text-tertiary">{getStatusText(currentJob.status)}</div>
              </div>
            </div>

            <div className="pipeline">
              {['queued', 'preprocessing', 'ocr', 'extracting', 'saved'].map((step, i) => {
                const stages = ['queued', 'preprocessing', 'ocr', 'extracting', 'saved'];
                const idx = stages.indexOf(currentJob.status);
                const isActive = i <= idx && currentJob.status !== 'failed';
                const isCurrent = i === idx;
                return (
                  <div key={step} className={`pipeline-step ${isActive ? 'active' : ''} ${isCurrent ? 'current' : ''}`}>
                    <div className="pipeline-dot">
                      {i < idx || currentJob.status === 'saved' ? <CheckCircle2 size={14} /> : i === idx && currentJob.status === 'failed' ? <AlertCircle size={14} /> : i + 1}
                    </div>
                    <span className="pipeline-label">{['Queue', 'OpenCV', 'OCR', 'SLM', 'SQLite'][i]}</span>
                  </div>
                );
              })}
            </div>

            <div className="progress-track">
              <div className="progress-fill" style={{ width: `${currentJob.progress}%` }} />
            </div>

            <div className="progress-info">
              <span>
                {currentJob.status === 'saved' ? 'Complete' : currentJob.status === 'failed' ? currentJob.error || 'Failed' : 'Processing on CPU...'}
              </span>
              <span className="font-mono">{currentJob.progress}%</span>
            </div>
          </div>
        )}
      </div>
    </div>
  );
};
