import { useState, useRef, useCallback } from 'react';
import { X, Upload } from 'lucide-react';

const TOKEN_KEY = 'auth_token';
function authHeader(): Record<string, string> {
  const t = localStorage.getItem(TOKEN_KEY);
  return t ? { Authorization: `Bearer ${t}` } : {};
}

interface Props {
  onClose: () => void;
  onComplete?: () => void;  // called when all uploads finish (indexed)
}

const REG_TYPES = ['EU Regulation', 'ISO Standard', 'National Draft', 'Internal Policy'];

// Backend DocumentStatus values and what stage they map to:
//   pending  → stage 0 (Preflight validation) in progress
//   stored   → stage 1 (Object storage upload) done, stage 2 starting
//   parsed   → stage 2 (Parse submission) done, stage 3 starting
//   indexed  → all stages done
//   failed   → error
type DocStatus = 'pending' | 'stored' | 'parsed' | 'indexed' | 'failed' | 'idle';

interface StageState {
  status: 'waiting' | 'running' | 'done' | 'error';
  progress: number; // 0–100
}

const STAGE_LABELS = [
  { name: 'Preflight validation',    desc: 'File-type validation, duplicate check, metadata' },
  { name: 'Object storage upload',   desc: 'File saved to document store' },
  { name: 'Parse submission',        desc: 'Aliyun DocMind / local parser — extracting structure' },
  { name: 'Chunking + embedding',    desc: 'Semantic blocks → vector chunks → 1024-d embeddings' },
];

function docStatusToStages(status: DocStatus): StageState[] {
  const waiting: StageState = { status: 'waiting', progress: 0 };
  const done:    StageState = { status: 'done',    progress: 100 };
  const running  = (p: number): StageState => ({ status: 'running', progress: p });

  switch (status) {
    case 'idle':    return [waiting, waiting, waiting, waiting];
    case 'pending': return [running(40), waiting, waiting, waiting];
    case 'stored':  return [done, done, running(30), waiting];
    case 'parsed':  return [done, done, done, running(60)];
    case 'indexed': return [done, done, done, done];
    case 'failed':  return [waiting, waiting, waiting, waiting]; // shown separately
    default:        return [waiting, waiting, waiting, waiting];
  }
}

export function UploadModal({ onClose, onComplete }: Props) {
  const [files, setFiles] = useState<File[]>([]);
  const [regType, setRegType] = useState(REG_TYPES[0]);
  const [version, setVersion] = useState('');
  const [dragging, setDragging] = useState(false);

  // Per-file processing state
  const [currentFileIdx, setCurrentFileIdx] = useState(-1);
  const [docStatus, setDocStatus] = useState<DocStatus>('idle');
  const [fileErrors, setFileErrors] = useState<string[]>([]);

  // Overall state
  const [submitting, setSubmitting] = useState(false);
  const [doneCount, setDoneCount] = useState(0);
  const [allDone, setAllDone] = useState(false);
  const [submitError, setSubmitError] = useState('');

  const fileInputRef = useRef<HTMLInputElement>(null);
  const pollTimer = useRef<ReturnType<typeof setInterval> | null>(null);

  function addFiles(newFiles: FileList | null) {
    if (!newFiles) return;
    setFiles(prev => [...prev, ...Array.from(newFiles)]);
  }

  function removeFile(index: number) {
    setFiles(prev => prev.filter((_, i) => i !== index));
  }

  function handleDrop(e: React.DragEvent) {
    e.preventDefault();
    setDragging(false);
    addFiles(e.dataTransfer.files);
  }

  function stopPolling() {
    if (pollTimer.current) {
      clearInterval(pollTimer.current);
      pollTimer.current = null;
    }
  }

  const pollStatus = useCallback((docId: string, resolve: () => void, reject: (msg: string) => void) => {
    let attempts = 0;
    const MAX_ATTEMPTS = 450; // 15 minutes at 2s interval — Aliyun DocMind can take several minutes
    stopPolling();
    pollTimer.current = setInterval(async () => {
      attempts++;
      try {
        const res = await fetch(`/api/v1/documents/status/${docId}`, { headers: authHeader() });
        if (!res.ok) {
          // Transient HTTP error (e.g. 502 during restart) — keep polling until timeout.
          if (attempts > MAX_ATTEMPTS) { stopPolling(); reject('Polling timeout'); }
          return;
        }
        const data: { status: string; message?: string } = await res.json();
        const status = data.status as DocStatus;
        setDocStatus(status);
        if (status === 'indexed') {
          stopPolling();
          resolve();
        } else if (status === 'failed') {
          stopPolling();
          reject(data.message ?? 'Processing failed');
        } else if (attempts > MAX_ATTEMPTS) {
          stopPolling();
          reject('Processing timeout (15 min) — check Document Management for status');
        }
      } catch {
        // network hiccup — keep polling
      }
    }, 2000);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  async function processFile(file: File, idx: number) {
    setCurrentFileIdx(idx);
    setDocStatus('idle');

    const form = new FormData();
    form.append('file', file);
    form.append('doc_name', file.name);
    form.append('regulation_type', regType);
    if (version) form.append('version', version);
    form.append('generate_summary', 'false');

    // Upload the file first — response contains the authoritative doc_id.
    // Without waiting here we risk polling an ID the server has not yet created.
    let docId: string;
    const uploadRes = await fetch('/api/v1/documents/upload', {
      method: 'POST',
      headers: authHeader(),
      body: form,
    });
    if (!uploadRes.ok) {
      const detail = await uploadRes.text().catch(() => uploadRes.statusText);
      throw new Error(`${file.name}: ${uploadRes.status} ${detail}`);
    }
    const uploadData = await uploadRes.json() as { doc_id: string; status: string };
    docId = uploadData.doc_id;

    // If backend processed synchronously (sync=true or status already 'indexed'), resolve immediately.
    if (uploadData.status === 'indexed') {
      setDocStatus('indexed');
      return;
    }
    if (uploadData.status === 'failed') {
      setDocStatus('failed');
      throw new Error(`${file.name}: Processing failed on server`);
    }

    // Otherwise start polling the authoritative doc_id returned by the server.
    setDocStatus(uploadData.status as DocStatus);
    await new Promise<void>((res, rej) => {
      pollStatus(docId, res, (msg: string) => rej(new Error(msg)));
    });
  }

  async function handleSubmit() {
    if (files.length === 0) return;
    setSubmitting(true);
    setSubmitError('');
    setDoneCount(0);
    setFileErrors([]);
    const errors: string[] = new Array(files.length).fill('');

    for (let i = 0; i < files.length; i++) {
      try {
        await processFile(files[i], i);
        setDoneCount(i + 1);
      } catch (e: unknown) {
        errors[i] = e instanceof Error ? e.message : String(e);
        setFileErrors([...errors]);
      }
    }

    setSubmitting(false);
    setAllDone(true);
    setDocStatus('idle');
    setCurrentFileIdx(-1);
    onComplete?.();  // notify parent to refresh doc list
  }

  // Compute queue stage display for the currently-processing file
  const stages = docStatusToStages(submitting ? docStatus : 'idle');

  const successCount = doneCount - fileErrors.filter(Boolean).length;

  if (allDone) {
    return (
      <div className="modal-overlay" onClick={onClose}>
        <div className="modal-dialog" style={{ gridTemplateColumns: '1fr', maxWidth: 480 }} onClick={e => e.stopPropagation()}>
          <div className="modal-panel" style={{ alignItems: 'center', justifyContent: 'center', textAlign: 'center', gap: 16, padding: 48 }}>
            <div style={{ width: 52, height: 52, borderRadius: '50%', background: 'var(--success-bg)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--success)', fontSize: 24 }}>✓</div>
            <div className="modal-title" style={{ fontSize: 18 }}>Import complete</div>
            <p className="modal-lead">
              {successCount} of {files.length} file{files.length > 1 ? 's' : ''} indexed successfully.
              {fileErrors.some(Boolean) && ' Some files failed — see Document Management for details.'}
            </p>
            <button className="btn primary" onClick={onClose}>Close</button>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-dialog" onClick={e => e.stopPropagation()}>
        <button className="modal-close" onClick={onClose} aria-label="Close" disabled={submitting}><X size={14} /></button>

        {/* ── Left panel: upload form ── */}
        <div className="modal-panel" style={{ overflowY: 'auto' }}>
          <div className="modal-eyebrow">Upload documents</div>
          <div className="modal-title">Stage files for parsing and indexing.</div>
          <p className="modal-lead">PDF, DOCX, TXT — one per API call, processed sequentially.</p>

          <input
            ref={fileInputRef}
            type="file"
            multiple
            accept=".pdf,.docx,.doc,.txt"
            style={{ display: 'none' }}
            onChange={e => addFiles(e.target.files)}
          />

          <div
            className={`dropzone${dragging ? ' drag-over' : ''}`}
            onDragOver={e => { e.preventDefault(); setDragging(true); }}
            onDragLeave={() => setDragging(false)}
            onDrop={handleDrop}
            onClick={() => !submitting && fileInputRef.current?.click()}
          >
            <div className="drop-icon">PDF</div>
            <div className="drop-label">Drop files here or browse</div>
            <p className="drop-hint">Up to 20 files · 200 MB combined</p>
            <div className="drop-actions">
              <button className="btn sm primary" onClick={e => { e.stopPropagation(); fileInputRef.current?.click(); }} disabled={submitting}>
                <Upload size={12} />Choose files
              </button>
            </div>
          </div>

          {files.length > 0 && (
            <div className="staged-files" style={{ maxHeight: 220, overflowY: 'auto', overflowX: 'hidden' }}>
              {files.map((f, i) => {
                const isDone   = doneCount > i;
                const isActive = submitting && currentFileIdx === i;
                const hasErr   = !!fileErrors[i];
                return (
                  <div key={i} className="file-row">
                    <div className="file-row-top">
                      <div>
                        <div className="file-name">{f.name}</div>
                        <div className="file-meta">{(f.size / 1024).toFixed(0)} KB · {f.type || 'document'}</div>
                      </div>
                      {!submitting && (
                        <button className="file-remove" onClick={() => removeFile(i)} aria-label="Remove"><X size={13} /></button>
                      )}
                      {isDone && !hasErr && <span className="status ok"  style={{ flexShrink: 0 }}>Indexed</span>}
                      {isDone && hasErr  && <span className="status risk" style={{ flexShrink: 0 }}>Failed</span>}
                      {isActive          && <span className="status info" style={{ flexShrink: 0 }}>
                        {docStatus === 'pending' ? 'Storing…'
                         : docStatus === 'stored' ? 'Parsing…'
                         : docStatus === 'parsed' ? 'Embedding…'
                         : 'Processing…'}
                      </span>}
                    </div>
                    <div className="file-progress">
                      <div className="file-progress-fill" style={{
                        width: isDone ? '100%'
                             : isActive ? `${docStatusToStages(docStatus)[3].progress || docStatusToStages(docStatus)[2].progress || docStatusToStages(docStatus)[0].progress || 20}%`
                             : '0%',
                        background: hasErr ? 'var(--danger)' : undefined,
                        transition: 'width 0.4s ease',
                      }} />
                    </div>
                  </div>
                );
              })}
            </div>
          )}

          <div className="upload-fields">
            <div className="upload-field">
              <label htmlFor="um-reg-type">Regulation type</label>
              <select id="um-reg-type" value={regType} onChange={e => setRegType(e.target.value)} disabled={submitting}>
                {REG_TYPES.map(t => <option key={t}>{t}</option>)}
              </select>
            </div>
            <div className="upload-field">
              <label htmlFor="um-version">Version / release</label>
              <input id="um-version" type="text" placeholder="e.g. 2024 final" value={version} onChange={e => setVersion(e.target.value)} disabled={submitting} />
            </div>
          </div>

          {submitError && <p style={{ color: 'var(--danger)', fontSize: 12, marginTop: 10 }}>{submitError}</p>}

          <div className="modal-actions">
            <button className="btn" onClick={onClose} disabled={submitting}>Cancel</button>
            <button className="btn primary" onClick={handleSubmit} disabled={files.length === 0 || submitting}>
              {submitting
                ? `Processing ${currentFileIdx + 1} / ${files.length}…`
                : 'Start import queue'}
            </button>
          </div>
        </div>

        {/* ── Right panel: live queue stages ── */}
        <div className="modal-panel">
          <div className="modal-eyebrow">Import queue</div>
          <div className="modal-title" style={{ fontSize: 18 }}>Live pipeline progress</div>
          <p className="modal-lead">Stages update in real time as each file moves through the processing pipeline.</p>

          <div className="summary-cards">
            <div className="summary-card-sm">
              <strong>{files.length} file{files.length !== 1 ? 's' : ''} staged</strong>
              <div className="summary-card-hint">
                {submitting ? `File ${currentFileIdx + 1} of ${files.length} — ${docStatus === 'idle' ? 'starting…' : docStatus}` : 'Ready for submission'}
              </div>
            </div>
            <div className="summary-card-sm">
              <strong>text-embedding-v3</strong>
              <div className="summary-card-hint">1024-d dense vectors, Milvus collection</div>
            </div>
          </div>

          <div className="queue-section">
            {STAGE_LABELS.map((stage, i) => {
              const s = stages[i];
              const statusCls = s.status === 'done' ? 'ok' : s.status === 'running' ? 'warn' : s.status === 'error' ? 'risk' : 'info';
              const label     = s.status === 'done' ? 'Done' : s.status === 'running' ? 'Running' : s.status === 'error' ? 'Error' : 'Waiting';
              return (
                <div key={stage.name} className="queue-card">
                  <div className="queue-top">
                    <div>
                      <div className="queue-name">{stage.name}</div>
                      <div className="queue-desc">{stage.desc}</div>
                    </div>
                    <span className={`status ${statusCls}`}>{label}</span>
                  </div>
                  <div className="queue-progress">
                    <div className="queue-progress-fill" style={{ width: `${s.progress}%`, transition: 'width 0.5s ease' }} />
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}
