/**
 * DocumentUploadPanel — Upload PDF do projektu + RAG re-ingest
 *
 * Auth: always via apiClient (Clerk Bearer from ApiInterceptor).
 * No query-string tokens (P0 security).
 */

import React, { useState, useEffect, useRef, useCallback } from 'react';
import { Upload, FileText, CheckCircle, XCircle, Loader2, RefreshCw, Trash2, AlertTriangle, Database, FileSearch } from 'lucide-react';
import toast from 'react-hot-toast';
import { apiClient, resolveApiBaseUrl } from '../../api/client';

interface ProjectDocument {
  doc_id: string;
  filename: string;
  file_size_bytes: number;
  status: 'uploaded' | 'processing' | 'indexed' | 'error';
  parser_used: string | null;
  chunks_count: number | null;
  error_message: string | null;
  uploaded_at: string;
  indexed_at: string | null;
}

interface QuotaInfo {
  current: number;
  limit: number;
  plan: string;
  can_upload: boolean;
}

interface Props {
  projectId: string;
  /** @deprecated ignored — auth via Clerk/apiClient only */
  token?: string;
}

// Kolor + ikona dla statusu indeksacji
function StatusBadge({ status }: { status: ProjectDocument['status'] }) {
  const map = {
    uploaded:   { label: 'Oczekuje',       color: '#f59e0b', bg: 'rgba(245,158,11,0.1)', Icon: Loader2 },
    processing: { label: 'Indeksowanie…',  color: '#3b82f6', bg: 'rgba(59,130,246,0.1)',  Icon: Loader2 },
    indexed:    { label: 'Gotowy',    color: '#10b981', bg: 'rgba(16,185,129,0.1)', Icon: CheckCircle },
    error:      { label: 'Błąd parsera',   color: '#ef4444', bg: 'rgba(239,68,68,0.1)',  Icon: XCircle },
  };
  const { label, color, bg, Icon } = map[status] ?? map.uploaded;
  const spinning = status === 'processing' || status === 'uploaded';

  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '2px 8px', borderRadius: 6, fontSize: '0.72rem',
      fontWeight: 700, background: bg, color,
    }}>
      <Icon size={11} style={spinning ? { animation: 'spin 1s linear infinite' } : {}} />
      {label}
    </span>
  );
}

function fmtBytes(b: number) {
  if (b < 1024) return `${b} B`;
  if (b < 1024 * 1024) return `${(b / 1024).toFixed(0)} KB`;
  return `${(b / (1024 * 1024)).toFixed(1)} MB`;
}

export default function DocumentUploadPanel({ projectId }: Props) {
  const [docs, setDocs] = useState<ProjectDocument[]>([]);
  const [quota, setQuota] = useState<QuotaInfo | null>(null);
  const [dragging, setDragging] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [loadingList, setLoadingList] = useState(true);
  const [docType, setDocType] = useState<'knowledge_base' | 'external_grant'>('knowledge_base');
  const fileInputRef = useRef<HTMLInputElement>(null);
  const pollingRef = useRef<ReturnType<typeof setInterval> | null>(null);

  /* ── Fetch listy dokumentów ────────────────────────────────────────────── */
  const fetchDocs = useCallback(async () => {
    try {
      const { data } = await apiClient.get(`/api/projects/${projectId}/documents`);
      setDocs(data.documents || []);
      if (data.quota) setQuota(data.quota);
    } catch {
      // sieć / 401 handled by interceptor
    } finally {
      setLoadingList(false);
    }
  }, [projectId]);

  /* ── Polling co 3s gdy jest document w trakcie przetwarzania ──────────── */
  useEffect(() => {
    fetchDocs();
  }, [fetchDocs]);

  useEffect(() => {
    const hasPending = docs.some(d => d.status === 'processing' || d.status === 'uploaded');
    if (hasPending && !pollingRef.current) {
      pollingRef.current = setInterval(fetchDocs, 3000);
    } else if (!hasPending && pollingRef.current) {
      clearInterval(pollingRef.current);
      pollingRef.current = null;
    }
    return () => {
      if (pollingRef.current) clearInterval(pollingRef.current);
    };
  }, [docs, fetchDocs]);

  /* ── Upload ────────────────────────────────────────────────────────────── */
  const uploadFile = async (file: File) => {
    if (!file.name.toLowerCase().endsWith('.pdf')) {
      toast.error('Obsługiwane są wyłącznie pliki PDF.');
      return;
    }
    if (file.size > 20 * 1024 * 1024) {
      toast.error('Plik przekracza limit 20 MB.');
      return;
    }
    if (quota && !quota.can_upload) {
      toast.error(
        quota.plan === 'free'
          ? `Osiągnięto limit ${quota.limit} plików na planie Free. Przejdź na plan Pro.`
          : `Osiągnięto limit ${quota.limit} plików dla tego projektu.`,
        { duration: 5000 }
      );
      return;
    }

    setUploading(true);
    const form = new FormData();
    form.append('file', file);

    try {
      const { data, status } = await apiClient.post(
        `/api/projects/${projectId}/documents`,
        form,
        {
          params: { doc_type: docType },
          headers: { 'Content-Type': 'multipart/form-data' },
          validateStatus: (s) => s < 500,
        }
      );
      if (status === 429) {
        const msg = typeof data?.detail === 'object'
          ? data.detail.message
          : data?.detail;
        toast.error(msg || 'Przekroczono limit plików dla tego planu.', { duration: 6000 });
        await fetchDocs();
      } else if (status >= 400) {
        toast.error(
          (typeof data?.detail === 'string' ? data.detail : data?.detail?.message) || 'Błąd uploadu.'
        );
      } else {
        toast.success(`📄 "${file.name}" wgrany. Przetwarzanie w toku…`);
        await fetchDocs();
      }
    } catch {
      toast.error('Błąd połączenia z serwerem.');
    } finally {
      setUploading(false);
    }
  };

  const onFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) uploadFile(file);
    e.target.value = '';
  };

  const onDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setDragging(false);
    const file = e.dataTransfer.files?.[0];
    if (file) uploadFile(file);
  };

  /* ── Re-ingest ─────────────────────────────────────────────────────────── */
  const reingest = async (docId: string) => {
    try {
      await apiClient.post(`/api/projects/${projectId}/documents/${docId}/reingest`);
      toast.success('Ponowna indeksacja uruchomiona.');
      fetchDocs();
    } catch {
      toast.error('Błąd ponownej indeksacji.');
    }
  };

  /* ── Delete ────────────────────────────────────────────────────────────── */
  const deleteDoc = async (docId: string, filename: string) => {
    if (!window.confirm(`Usunąć "${filename}" z projektu?`)) return;
    try {
      await apiClient.delete(`/api/projects/${projectId}/documents/${docId}`);
      toast.success('Dokument usunięty.');
      setDocs(d => d.filter(x => x.doc_id !== docId));
    } catch {
      toast.error('Błąd usuwania.');
    }
  };

  /* ── Render ────────────────────────────────────────────────────────────── */
  const baseHint = resolveApiBaseUrl(import.meta.env.VITE_API_URL);

  return (
    <div style={{ maxWidth: 820, margin: '2rem auto', padding: '0 1rem', display: 'flex', flexDirection: 'column', gap: '1.5rem' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <Database size={20} color="#3b82f6" />
        <div>
          <h3 style={{ margin: 0, fontSize: '1.05rem' }}>Baza wiedzy projektu (RAG)</h3>
          <p style={{ margin: '4px 0 0', fontSize: '0.8rem', color: '#64748b' }}>
            PDF regulaminów i dokumentów firmowych — indeksowane do dopasowań i generatora.
          </p>
        </div>
      </div>

      {quota && (
        <div style={{
          fontSize: '0.8rem', color: quota.can_upload ? '#64748b' : '#b45309',
          padding: '8px 12px', borderRadius: 8,
          background: quota.can_upload ? 'rgba(100,116,139,0.08)' : 'rgba(245,158,11,0.12)',
        }}>
          Limit: {quota.current}/{quota.limit} plików (plan {quota.plan})
        </div>
      )}

      <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
        <button
          type="button"
          onClick={() => setDocType('knowledge_base')}
          style={{
            padding: '6px 12px', borderRadius: 8, border: '1px solid #e2e8f0',
            background: docType === 'knowledge_base' ? '#eff6ff' : '#fff',
            fontWeight: 600, fontSize: '0.8rem', cursor: 'pointer',
          }}
        >
          <FileSearch size={14} style={{ verticalAlign: 'middle', marginRight: 4 }} />
          Baza wiedzy
        </button>
        <button
          type="button"
          onClick={() => setDocType('external_grant')}
          style={{
            padding: '6px 12px', borderRadius: 8, border: '1px solid #e2e8f0',
            background: docType === 'external_grant' ? '#eff6ff' : '#fff',
            fontWeight: 600, fontSize: '0.8rem', cursor: 'pointer',
          }}
        >
          <FileText size={14} style={{ verticalAlign: 'middle', marginRight: 4 }} />
          Wniosek / regulamin zewnętrzny
        </button>
      </div>

      <div
        onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
        onDragLeave={() => setDragging(false)}
        onDrop={onDrop}
        onClick={() => fileInputRef.current?.click()}
        style={{
          border: `2px dashed ${dragging ? '#3b82f6' : '#cbd5e1'}`,
          borderRadius: 12, padding: '2rem', textAlign: 'center',
          background: dragging ? 'rgba(59,130,246,0.06)' : '#f8fafc',
          cursor: uploading ? 'wait' : 'pointer',
        }}
      >
        <input
          ref={fileInputRef}
          type="file"
          accept="application/pdf,.pdf"
          style={{ display: 'none' }}
          onChange={onFileChange}
        />
        {uploading ? (
          <Loader2 size={28} style={{ animation: 'spin 1s linear infinite', color: '#3b82f6' }} />
        ) : (
          <Upload size={28} color="#64748b" />
        )}
        <p style={{ margin: '12px 0 0', fontWeight: 600 }}>
          {uploading ? 'Wysyłanie…' : 'Upuść PDF lub kliknij, aby wybrać'}
        </p>
        <p style={{ margin: '6px 0 0', fontSize: '0.75rem', color: '#94a3b8' }}>
          Max 20 MB · API: {baseHint || 'relative'}
        </p>
      </div>

      {loadingList ? (
        <div style={{ color: '#94a3b8', fontSize: '0.85rem' }}>Ładowanie listy…</div>
      ) : docs.length === 0 ? (
        <div style={{
          display: 'flex', alignItems: 'center', gap: 8,
          padding: 12, borderRadius: 8, background: 'rgba(245,158,11,0.08)', color: '#92400e',
          fontSize: '0.85rem',
        }}>
          <AlertTriangle size={16} />
          Brak wgranych dokumentów. Dodaj regulamin programu dla wiarygodnej generacji.
        </div>
      ) : (
        <ul style={{ listStyle: 'none', margin: 0, padding: 0, display: 'flex', flexDirection: 'column', gap: 8 }}>
          {docs.map((d) => (
            <li
              key={d.doc_id}
              style={{
                display: 'flex', alignItems: 'center', gap: 12,
                padding: '10px 12px', borderRadius: 10, border: '1px solid #e2e8f0', background: '#fff',
              }}
            >
              <FileText size={18} color="#64748b" />
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 600, fontSize: '0.9rem', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                  {d.filename}
                </div>
                <div style={{ fontSize: '0.72rem', color: '#94a3b8' }}>
                  {fmtBytes(d.file_size_bytes || 0)}
                  {d.chunks_count != null ? ` · ${d.chunks_count} chunków` : ''}
                  {d.parser_used ? ` · ${d.parser_used}` : ''}
                </div>
                {d.error_message && (
                  <div style={{ fontSize: '0.72rem', color: '#ef4444' }}>{d.error_message}</div>
                )}
              </div>
              <StatusBadge status={d.status} />
              <button type="button" title="Re-ingest" onClick={() => reingest(d.doc_id)}
                style={{ border: 'none', background: 'transparent', cursor: 'pointer', padding: 4 }}>
                <RefreshCw size={15} color="#64748b" />
              </button>
              <button type="button" title="Usuń" onClick={() => deleteDoc(d.doc_id, d.filename)}
                style={{ border: 'none', background: 'transparent', cursor: 'pointer', padding: 4 }}>
                <Trash2 size={15} color="#ef4444" />
              </button>
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}
