import React, { useState, useRef, useCallback } from 'react';
import { importFile, type ImportFileResult } from '../../api.js';
import { useModalDismiss } from './useModalDismiss.js';

interface ImportFilesModalProps {
  open: boolean;
  onClose: () => void;
  contextGraphId: string;
  contextGraphName?: string;
}

interface QueuedFile {
  file: File;
  id: string;
}

type UploadStatus = 'idle' | 'uploading' | 'done' | 'error';

interface UploadResult {
  fileName: string;
  status: 'success' | 'skipped' | 'error';
  triplesWritten?: number;
  error?: string;
}

const SUPPORTED_EXTENSIONS = '.md, .docx, .pdf, .txt, .csv, .json, .ttl, .rdf, .owl, .py, .ts, .js, .tsx, .jsx, .java, .go, .rs, .c, .cpp, .html, .xml, .yaml, .yml';

function formatSize(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

function fileIcon(name: string): string {
  const ext = name.split('.').pop()?.toLowerCase() ?? '';
  if (['md', 'txt'].includes(ext)) return '📝';
  if (['pdf'].includes(ext)) return '📕';
  if (['docx', 'doc'].includes(ext)) return '📄';
  if (['csv', 'json', 'xml', 'yaml', 'yml'].includes(ext)) return '📊';
  if (['ttl', 'rdf', 'owl'].includes(ext)) return '🔗';
  if (['py', 'ts', 'js', 'tsx', 'jsx', 'java', 'go', 'rs', 'c', 'cpp'].includes(ext)) return '💻';
  if (['png', 'jpg', 'jpeg', 'webp'].includes(ext)) return '🖼️';
  return '📄';
}

export function ImportFilesModal({ open, onClose, contextGraphId, contextGraphName }: ImportFilesModalProps) {
  const [files, setFiles] = useState<QueuedFile[]>([]);
  const [extractKnowledge, setExtractKnowledge] = useState(true);
  const [storeOriginals, setStoreOriginals] = useState(true);
  const [status, setStatus] = useState<UploadStatus>('idle');
  const [currentFile, setCurrentFile] = useState(0);
  const [results, setResults] = useState<UploadResult[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [dragOver, setDragOver] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  const addFiles = useCallback((newFiles: FileList | File[]) => {
    const arr = Array.from(newFiles);
    setFiles(prev => {
      const existing = new Set(prev.map(f => `${f.file.name}:${f.file.size}`));
      const unique = arr.filter(f => !existing.has(`${f.name}:${f.size}`));
      return [...prev, ...unique.map(f => ({ file: f, id: `${f.name}-${f.size}-${Date.now()}` }))];
    });
  }, []);

  const removeFile = (id: string) => {
    setFiles(prev => prev.filter(f => f.id !== id));
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragOver(true);
  };

  const handleDragLeave = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragOver(false);
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragOver(false);
    if (e.dataTransfer.files.length > 0) {
      addFiles(e.dataTransfer.files);
    }
  };

  const handleImport = async () => {
    if (files.length === 0) return;

    setStatus('uploading');
    setCurrentFile(0);
    setResults([]);
    setError(null);

    const uploadResults: UploadResult[] = [];

    for (let i = 0; i < files.length; i++) {
      setCurrentFile(i);
      const { file } = files[i];
      const sanitized = file.name.replace(/[^a-zA-Z0-9._-]/g, '_');
      const assertionName = `${Date.now().toString(36)}-${i}-${sanitized}`;

      try {
        const result: ImportFileResult = await importFile(assertionName, contextGraphId, file);
        const triples = result.extraction.tripleCount ?? result.extraction.triplesWritten;
        uploadResults.push({
          fileName: file.name,
          status: result.extraction.status === 'completed' ? 'success' :
                  result.extraction.status === 'skipped' ? 'skipped' : 'error',
          triplesWritten: triples,
          error: result.extraction.error,
        });
      } catch (err: any) {
        uploadResults.push({
          fileName: file.name,
          status: 'error',
          error: err?.message ?? 'Upload failed',
        });
      }
    }

    setResults(uploadResults);
    setCurrentFile(files.length);

    const hasErrors = uploadResults.some(r => r.status === 'error');
    setStatus(hasErrors ? 'error' : 'done');
  };

  const handleClose = () => {
    if (status === 'uploading') return;
    setFiles([]);
    setResults([]);
    setStatus('idle');
    setError(null);
    setCurrentFile(0);
    onClose();
  };

  // Esc-to-close + Tab focus-trap + focus-restore, same as Create/Join.
  // `handleClose` already no-ops while an import is in flight, so Esc and
  // backdrop-click both inherit that guard.
  const { dialogRef, onBackdropClick } = useModalDismiss(open, handleClose);

  if (!open) return null;

  const totalTriples = results.reduce((sum, r) => sum + (r.triplesWritten ?? 0), 0);
  const successCount = results.filter(r => r.status === 'success').length;
  const skippedCount = results.filter(r => r.status === 'skipped').length;
  const errorCount = results.filter(r => r.status === 'error').length;

  return (
    <div className="v10-modal-overlay" onClick={onBackdropClick} role="presentation">
      <div
        className="v10-modal-box"
        style={{ maxWidth: 560 }}
        ref={dialogRef}
        role="dialog"
        aria-modal="true"
        aria-labelledby="dkg-import-modal-title"
      >
        {/* Header is a flex row so the × sits inline in the header flow
            (no absolute positioning — `.v10-modal-box` is position:static,
            so an absolutely-positioned button would anchor to the overlay
            viewport instead of the modal; see #959 Codex review). */}
        <div
          className="v10-modal-header"
          style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}
        >
          <div style={{ flex: 1, minWidth: 0 }}>
            <div id="dkg-import-modal-title" className="v10-modal-title">Import to Working Memory</div>
            <div className="v10-modal-subtitle">
              {contextGraphName
                ? <>Upload files to <strong>{contextGraphName}</strong> — your agent will extract structured knowledge.</>
                : <>Upload files — your agent will extract structured knowledge and add it to working memory.</>
              }
            </div>
          </div>
          <button
            type="button"
            className="v10-modal-close"
            onClick={handleClose}
            disabled={status === 'uploading'}
            aria-label="Close import dialog"
            title="Close (Esc)"
            style={{ flexShrink: 0, cursor: status === 'uploading' ? 'not-allowed' : 'pointer' }}
          >
            ×
          </button>
        </div>

        <div className="v10-modal-body">
          {error && <div className="v10-modal-error">{error}</div>}

          {status === 'idle' && (
            <>
              <div
                className={`v10-import-dropzone ${dragOver ? 'drag-over' : ''}`}
                onClick={() => inputRef.current?.click()}
                onDragOver={handleDragOver}
                onDragLeave={handleDragLeave}
                onDrop={handleDrop}
              >
                <div className="v10-import-dropzone-label">
                  Drag files here, or click to browse
                </div>
                <div className="v10-import-dropzone-hint" style={{ marginTop: 4 }}>
                  Your agent will extract structured knowledge and add it to working memory.
                </div>
                <div className="v10-import-dropzone-hint" style={{ marginTop: 8 }}>
                  Supported: {SUPPORTED_EXTENSIONS}
                </div>
                <input
                  ref={inputRef}
                  type="file"
                  multiple
                  style={{ display: 'none' }}
                  onChange={(e) => { if (e.target.files) addFiles(e.target.files); e.target.value = ''; }}
                />
              </div>

              {files.length > 0 && (
                <>
                  <div className="v10-import-file-list">
                    {files.map((f) => (
                      <div key={f.id} className="v10-import-file-item">
                        <span className="v10-import-file-icon">{fileIcon(f.file.name)}</span>
                        <span className="v10-import-file-name">{f.file.name}</span>
                        <span className="v10-import-file-size">{formatSize(f.file.size)}</span>
                        <button className="v10-import-file-remove" onClick={() => removeFile(f.id)} title="Remove">×</button>
                      </div>
                    ))}
                  </div>
                  <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginBottom: 12 }}>
                    {files.length} file{files.length !== 1 ? 's' : ''} selected · {formatSize(files.reduce((s, f) => s + f.file.size, 0))} total
                  </div>
                </>
              )}

              <div className="v10-form-divider" />
              <div className="v10-form-label" style={{ marginBottom: 8 }}>Ingestion Options <span style={{ fontSize: 10, fontWeight: 400, color: 'var(--text-tertiary)' }}>(coming soon)</span></div>
              <label className="v10-import-option" style={{ opacity: 0.5, pointerEvents: 'none' }}>
                <input type="checkbox" checked={storeOriginals} disabled readOnly />
                Store original files as Knowledge Assets
              </label>
              <label className="v10-import-option" style={{ opacity: 0.5, pointerEvents: 'none' }}>
                <input type="checkbox" checked={extractKnowledge} disabled readOnly />
                Let agent extract structured knowledge from content
              </label>
            </>
          )}

          {status === 'uploading' && (
            <div className="v10-import-progress">
              <div style={{ fontSize: 12, color: 'var(--text-secondary)', fontWeight: 500 }}>
                Importing files… ({currentFile + 1} of {files.length})
              </div>
              <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 4 }}>
                {files[currentFile]?.file.name ?? '…'}
              </div>
              <div className="v10-import-progress-bar">
                <div
                  className="v10-import-progress-fill"
                  style={{ width: `${((currentFile + 0.5) / files.length) * 100}%` }}
                />
              </div>
              <div className="v10-import-progress-text">
                {currentFile} of {files.length} files processed
              </div>
            </div>
          )}

          {(status === 'done' || status === 'error') && (
            <>
              <div
                className={`v10-import-result ${errorCount > 0 ? 'error' : 'success'}`}
                data-testid="import-result"
                data-import-status={errorCount > 0 ? 'error' : 'success'}
                data-import-triples={totalTriples}
              >
                {errorCount === 0 ? (
                  <>
                    {successCount > 0 && (
                      <>
                        Successfully imported {successCount} file{successCount !== 1 ? 's' : ''}.
                        {totalTriples > 0 && <> Extracted <strong>{totalTriples.toLocaleString()}</strong> triples into working memory.</>}
                      </>
                    )}
                    {skippedCount > 0 && (
                      <>
                        {successCount > 0 ? ' ' : ''}
                        Stored {skippedCount} file{skippedCount !== 1 ? 's' : ''} as source — no structured knowledge was extracted yet (extraction for these file types is coming soon).
                      </>
                    )}
                  </>
                ) : (
                  <>
                    {successCount} file{successCount !== 1 ? 's' : ''} imported
                    {skippedCount > 0 && <>, {skippedCount} stored without extraction</>}
                    , {errorCount} failed.
                    {totalTriples > 0 && <> {totalTriples.toLocaleString()} triples extracted.</>}
                  </>
                )}
              </div>

              {results.length > 0 && (
                <div className="v10-import-file-list" style={{ marginTop: 12 }}>
                  {results.map((r, i) => (
                    <div key={i} className="v10-import-file-item">
                      <span className="v10-import-file-icon">
                        {r.status === 'success' ? '✓' : r.status === 'skipped' ? '–' : '✗'}
                      </span>
                      <span className="v10-import-file-name">{r.fileName}</span>
                      <span className="v10-import-file-size" style={r.status === 'error' ? { color: 'var(--text-danger)' } : undefined}>
                        {r.status === 'success' && r.triplesWritten != null ? `${r.triplesWritten} triples` :
                         r.status === 'skipped' ? 'stored (no extraction)' :
                         r.error ?? 'failed'}
                      </span>
                    </div>
                  ))}
                </div>
              )}
            </>
          )}
        </div>

        <div className="v10-modal-footer">
          {status === 'idle' && (
            <>
              <button className="v10-modal-btn" onClick={handleClose}>Cancel</button>
              <button
                className="v10-modal-btn primary"
                onClick={handleImport}
                disabled={files.length === 0}
              >
                Start Import ({files.length} file{files.length !== 1 ? 's' : ''})
              </button>
            </>
          )}
          {status === 'uploading' && (
            <button className="v10-modal-btn" disabled>Importing…</button>
          )}
          {(status === 'done' || status === 'error') && (
            <button className="v10-modal-btn primary" onClick={handleClose}>Done</button>
          )}
        </div>
      </div>
    </div>
  );
}
