import { useState, useRef, useCallback } from "react";
import { useMutation } from "@tanstack/react-query";
import {
  Upload,
  Download,
  FileJson,
  CheckCircle,
  XCircle,
  AlertTriangle,
  Loader2,
  ChevronDown,
  ChevronUp,
  ImageIcon,
  Copy,
  Check,
  Trash2,
  Braces,
} from "lucide-react";
import { importRT, type RTImportPayload, type RTTechniqueEntry, type RTEvidenceEntry } from "../api/tests";

/* ── Template JSON ─────────────────────────────────────────────────── */

// Tiny 1×1 pixel red PNG — used only as placeholder in the downloadable template.
// Operators must replace this with real base64-encoded screenshots.
const PLACEHOLDER_B64 =
  "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADklEQVQI12P4z8BQDwADhQGAWjR9awAAAABJRU5ErkJggg==";

const TEMPLATE_JSON: RTImportPayload = {
  name: "Red Team Q1 2024",
  date: new Date().toISOString().slice(0, 10),
  description: "External red team engagement — perimeter assessment",
  operator: "SecTeam Red",
  techniques: [
    {
      mitre_id: "T1059.001",
      result: "detected",
      attack_success: "successful",
      platform: "windows",
      notes: "PowerShell execution caught by Defender for Endpoint within 2 min",
      evidence: [
        {
          filename: "edr_alert_powershell.png",
          data: PLACEHOLDER_B64,
          caption: "EDR alert showing PowerShell execution blocked",
        },
      ],
    },
    {
      mitre_id: "T1078",
      result: "not_detected",
      attack_success: "successful",
      platform: "windows",
      notes: "Credential reuse via stolen credentials — undetected for 48h",
      evidence: [
        {
          filename: "logon_event_4624.png",
          data: PLACEHOLDER_B64,
          caption: "Windows event log showing lateral movement logon",
        },
        {
          filename: "timeline_activity.png",
          data: PLACEHOLDER_B64,
          caption: "48h activity timeline without any alert",
        },
      ],
    },
    {
      mitre_id: "T1486",
      result: "not_detected",
      attack_success: "not_successful",
      platform: "windows",
      notes: "Ransomware blocked by AppLocker before execution",
      evidence: [
        {
          filename: "applocker_block.png",
          data: PLACEHOLDER_B64,
          caption: "AppLocker event log blocking ransomware binary",
        },
      ],
    },
    {
      mitre_id: "T1190",
      result: "partially_detected",
      attack_success: "partially_successful",
      platform: "linux",
      notes: "Exploit worked but only a partial alert fired — no full incident created",
      evidence: [
        {
          filename: "partial_alert.png",
          data: PLACEHOLDER_B64,
          caption: "SIEM alert showing partial detection — no incident created",
        },
      ],
    },
  ],
};

/* ── helpers ─────────────────────────────────────────────────────── */

const RESULT_CONFIG: Record<string, { label: string; badge: string }> = {
  detected:           { label: "Detected",          badge: "bg-green-500/10 text-green-400 border-green-500/20" },
  not_detected:       { label: "Not Detected",       badge: "bg-red-500/10 text-red-400 border-red-500/20" },
  partially_detected: { label: "Partial",            badge: "bg-yellow-500/10 text-yellow-400 border-yellow-500/20" },
};

function downloadTemplate() {
  const blob = new Blob([JSON.stringify(TEMPLATE_JSON, null, 2)], { type: "application/json" });
  const a = document.createElement("a");
  a.href = URL.createObjectURL(blob);
  a.download = "rt_import_template.json";
  a.click();
  URL.revokeObjectURL(a.href);
}

function parseJson(raw: string): { payload: RTImportPayload | null; error: string | null } {
  try {
    const parsed = JSON.parse(raw);
    if (!parsed.name) return { payload: null, error: "Missing required field: name" };
    if (!Array.isArray(parsed.techniques)) return { payload: null, error: "Missing required field: techniques (array)" };
    for (const t of parsed.techniques) {
      if (!t.mitre_id) return { payload: null, error: `Technique missing mitre_id: ${JSON.stringify(t)}` };
      if (!["detected", "not_detected", "partially_detected"].includes(t.result)) {
        return { payload: null, error: `Invalid result '${t.result}' for ${t.mitre_id}. Must be: detected | not_detected | partially_detected` };
      }
      // Evidence is mandatory
      if (!Array.isArray(t.evidence) || t.evidence.length === 0) {
        return { payload: null, error: `Technique ${t.mitre_id} is missing evidence. At least one image is required per technique (evidence[].filename + evidence[].data in base64).` };
      }
      for (const ev of t.evidence as RTEvidenceEntry[]) {
        if (!ev.filename || typeof ev.filename !== "string") {
          return { payload: null, error: `Evidence in ${t.mitre_id} is missing filename.` };
        }
        if (!ev.data || typeof ev.data !== "string") {
          return { payload: null, error: `Evidence '${ev.filename}' in ${t.mitre_id} is missing base64 data.` };
        }
      }
    }
    return { payload: parsed as RTImportPayload, error: null };
  } catch (e) {
    return { payload: null, error: `Invalid JSON: ${(e as Error).message}` };
  }
}

/* ── Component ────────────────────────────────────────────────────── */

export default function ImportRTPage() {
  const fileRef = useRef<HTMLInputElement>(null);
  const [jsonText, setJsonText] = useState("");
  const [showFormat, setShowFormat] = useState(false);
  const [parseError, setParseError] = useState<string | null>(null);
  const [preview, setPreview] = useState<RTImportPayload | null>(null);

  const importMutation = useMutation({
    mutationFn: (payload: RTImportPayload) => importRT(payload),
  });

  const handleTextChange = (value: string) => {
    setJsonText(value);
    setParseError(null);
    importMutation.reset();
    if (!value.trim()) {
      setPreview(null);
      return;
    }
    const { payload, error } = parseJson(value);
    if (error) {
      setParseError(error);
      setPreview(null);
    } else {
      setPreview(payload);
    }
  };

  const handleFile = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (ev) => {
      const text = ev.target?.result as string;
      setJsonText(text);
      handleTextChange(text);
    };
    reader.readAsText(file);
    e.target.value = "";
  };

  const handleImport = () => {
    if (!preview) return;
    importMutation.mutate(preview);
  };

  const result = importMutation.data;

  return (
    <div className="space-y-6 max-w-4xl">
      {/* Header */}
      <div>
        <h1 className="text-2xl font-bold text-white flex items-center gap-2">
          <Upload className="h-7 w-7 text-orange-400" />
          Import Red Team Results
        </h1>
        <p className="mt-1 text-sm text-gray-400">
          Upload findings from a real Red Team engagement. Each technique creates a test in
          <span className="text-blue-400"> In Review</span> state — Red side is pre-approved by the RT,
          Blue Lead must still validate the detection result before it counts as coverage.
        </p>
      </div>

      {/* Format toggle */}
      <div className="rounded-xl border border-gray-800 bg-gray-900">
        <button
          onClick={() => setShowFormat(!showFormat)}
          className="flex w-full items-center justify-between px-5 py-4 text-left"
        >
          <div className="flex items-center gap-2">
            <FileJson className="h-4 w-4 text-cyan-400" />
            <span className="text-sm font-medium text-gray-300">JSON Format Reference</span>
          </div>
          {showFormat ? <ChevronUp className="h-4 w-4 text-gray-500" /> : <ChevronDown className="h-4 w-4 text-gray-500" />}
        </button>

        {showFormat && (
          <div className="border-t border-gray-800 px-5 pb-5 pt-4 space-y-4">
            <div className="grid gap-4 sm:grid-cols-2">
              {/* Required fields */}
              <div>
                <p className="mb-2 text-xs font-semibold uppercase tracking-wider text-gray-500">Required fields</p>
                <table className="w-full text-xs">
                  <tbody className="divide-y divide-gray-800">
                    {[
                      ["name", "string", "Engagement name"],
                      ["techniques[].mitre_id", "string", "e.g. T1059.001"],
                      ["techniques[].result", "enum", "detected | not_detected | partially_detected"],
                      ["techniques[].attack_success", "enum", "successful | not_successful | partially_successful"],
                      ["techniques[].evidence", "array", "Min 1 image required per technique"],
                      ["techniques[].evidence[].filename", "string", "e.g. screenshot_edr.png"],
                      ["techniques[].evidence[].data", "string", "Base64-encoded image (PNG/JPG/GIF/WebP/BMP, max 10 MB)"],
                    ].map(([field, type, desc]) => (
                      <tr key={field}>
                        <td className="py-1.5 pr-3 font-mono text-cyan-400">{field}</td>
                        <td className="py-1.5 pr-3 text-gray-500 italic">{type}</td>
                        <td className="py-1.5 text-gray-400">{desc}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
              {/* Optional fields */}
              <div>
                <p className="mb-2 text-xs font-semibold uppercase tracking-wider text-gray-500">Optional fields</p>
                <table className="w-full text-xs">
                  <tbody className="divide-y divide-gray-800">
                    {[
                      ["date", "string", "ISO date (YYYY-MM-DD)"],
                      ["description", "string", "Engagement description"],
                      ["operator", "string", "Team or company"],
                      ["techniques[].platform", "string", "windows | linux | macos"],
                      ["techniques[].notes", "string", "What happened, how it was used"],
                      ["techniques[].evidence[].caption", "string", "Description of what the image shows"],
                    ].map(([field, type, desc]) => (
                      <tr key={field}>
                        <td className="py-1.5 pr-3 font-mono text-gray-400">{field}</td>
                        <td className="py-1.5 pr-3 text-gray-500 italic">{type}</td>
                        <td className="py-1.5 text-gray-400">{desc}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            </div>

            <button
              onClick={downloadTemplate}
              className="flex items-center gap-2 rounded-lg border border-cyan-500/30 bg-cyan-500/10 px-4 py-2 text-sm font-medium text-cyan-400 hover:bg-cyan-500/20 transition-colors"
            >
              <Download className="h-4 w-4" />
              Download template JSON
            </button>
          </div>
        )}
      </div>

      {/* Input area */}
      <div className="rounded-xl border border-gray-800 bg-gray-900 p-5 space-y-4">
        <div className="flex items-center justify-between">
          <h2 className="text-sm font-semibold text-white">Paste or upload your JSON</h2>
          <div className="flex items-center gap-2">
            <input ref={fileRef} type="file" accept=".json" onChange={handleFile} className="hidden" />
            <button
              onClick={() => fileRef.current?.click()}
              className="flex items-center gap-1.5 rounded-lg border border-gray-700 px-3 py-1.5 text-xs text-gray-400 hover:bg-gray-800 hover:text-white transition-colors"
            >
              <Upload className="h-3.5 w-3.5" />
              Upload file
            </button>
          </div>
        </div>

        <textarea
          value={jsonText}
          onChange={(e) => handleTextChange(e.target.value)}
          placeholder={`Paste your JSON here or use the template…\n\n{\n  "name": "Red Team Q1 2024",\n  "techniques": [\n    {\n      "mitre_id": "T1059.001",\n      "result": "detected",\n      "attack_success": "successful"\n    }\n  ]\n}`}
          rows={14}
          className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-2.5 font-mono text-xs text-gray-200 placeholder-gray-600 focus:border-cyan-500 focus:outline-none resize-none"
        />

        {parseError && (
          <div className="flex items-start gap-2 rounded-lg border border-red-500/30 bg-red-900/20 p-3 text-sm text-red-400">
            <XCircle className="h-4 w-4 mt-0.5 shrink-0" />
            {parseError}
          </div>
        )}
      </div>

      {/* Preview */}
      {preview && !parseError && (
        <div className="rounded-xl border border-gray-800 bg-gray-900 p-5 space-y-4">
          <div className="flex items-center justify-between">
            <div>
              <h2 className="text-sm font-semibold text-white">{preview.name}</h2>
              <p className="mt-0.5 text-xs text-gray-500">
                {preview.date && <span>{preview.date} · </span>}
                {preview.operator && <span>{preview.operator} · </span>}
                <span className="text-amber-400">{preview.techniques.length} techniques</span>
              </p>
              {preview.description && (
                <p className="mt-1 text-xs text-gray-400">{preview.description}</p>
              )}
            </div>
            <button
              onClick={handleImport}
              disabled={importMutation.isPending}
              className="flex items-center gap-2 rounded-lg bg-orange-600 px-4 py-2 text-sm font-medium text-white hover:bg-orange-500 disabled:opacity-50 transition-colors"
            >
              {importMutation.isPending
                ? <><Loader2 className="h-4 w-4 animate-spin" /> Importing…</>
                : <><Upload className="h-4 w-4" /> Import {preview.techniques.length} Techniques</>
              }
            </button>
          </div>

          <div className="overflow-x-auto rounded-lg border border-gray-800">
            <table className="w-full text-xs">
              <thead>
                <tr className="border-b border-gray-800 text-gray-500 uppercase tracking-wider">
                  <th className="px-4 py-2.5 text-left">MITRE ID</th>
                  <th className="px-4 py-2.5 text-left">Result</th>
                  <th className="px-4 py-2.5 text-left">Attack</th>
                  <th className="px-4 py-2.5 text-left">Platform</th>
                  <th className="px-4 py-2.5 text-left">Notes</th>
                  <th className="px-4 py-2.5 text-left">Evidence</th>
                </tr>
              </thead>
              <tbody className="divide-y divide-gray-800/50">
                {preview.techniques.map((t: RTTechniqueEntry, i) => (
                  <tr key={i} className="hover:bg-gray-800/20">
                    <td className="px-4 py-2.5 font-mono text-cyan-400 font-semibold">{t.mitre_id}</td>
                    <td className="px-4 py-2.5">
                      <span className={`inline-flex rounded-full border px-2 py-0.5 font-medium ${RESULT_CONFIG[t.result]?.badge ?? ""}`}>
                        {RESULT_CONFIG[t.result]?.label ?? t.result}
                      </span>
                    </td>
                    <td className="px-4 py-2.5">
                      {t.attack_success === "successful" ? (
                        <span className="text-orange-400">Success</span>
                      ) : t.attack_success === "partially_successful" ? (
                        <span className="text-yellow-400">Partial</span>
                      ) : (
                        <span className="text-gray-500">Blocked</span>
                      )}
                    </td>
                    <td className="px-4 py-2.5 text-gray-400 capitalize">{t.platform ?? "—"}</td>
                    <td className="px-4 py-2.5 text-gray-500 max-w-xs truncate">{t.notes ?? "—"}</td>
                    <td className="px-4 py-2.5">
                      {t.evidence && t.evidence.length > 0 ? (
                        <div className="flex items-center gap-1.5">
                          <div className="flex gap-1">
                            {t.evidence.slice(0, 3).map((ev: RTEvidenceEntry, ei: number) => {
                              const SAFE_MIMES: Record<string, string> = {
                                png: "image/png", jpg: "image/jpeg", jpeg: "image/jpeg",
                                gif: "image/gif", webp: "image/webp",
                              };
                              const ext = ev.filename.split(".").pop()?.toLowerCase() ?? "";
                              const mime = SAFE_MIMES[ext] ?? "image/png";
                              return (
                                <img
                                  key={ei}
                                  src={`data:${mime};base64,${ev.data}`}
                                  title={ev.caption ?? ev.filename}
                                  className="h-7 w-7 rounded object-cover border border-gray-700"
                                />
                              );
                            })}
                            {t.evidence.length > 3 && (
                              <span className="flex h-7 w-7 items-center justify-center rounded border border-gray-700 bg-gray-800 text-xs text-gray-400">
                                +{t.evidence.length - 3}
                              </span>
                            )}
                          </div>
                          <span className="text-xs text-gray-500">{t.evidence.length} img</span>
                        </div>
                      ) : (
                        <span className="text-xs text-red-400">⚠ Missing</span>
                      )}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {/* Import result */}
      {result && (
        <div className="rounded-xl border border-green-500/30 bg-green-500/5 p-5 space-y-3">
          <div className="flex items-center gap-2">
            <CheckCircle className="h-5 w-5 text-green-400" />
            <h2 className="text-sm font-semibold text-green-400">
              Import complete — {result.created} tests created
            </h2>
          </div>
          <p className="text-xs text-gray-400">
            Engagement: <span className="text-white">{result.engagement}</span>
            {" · "}Created: <span className="text-green-400">{result.created}</span>
            {" · "}Evidence: <span className="text-cyan-400">
              {result.items.reduce((sum, it) => sum + (it.evidence_attached ?? 0), 0)} images attached
            </span>
            {result.skipped > 0 && <>{" · "}<span className="text-yellow-400">{result.skipped} skipped</span></>}
          </p>

          {result.warnings.length > 0 && (
            <div className="space-y-1">
              <p className="text-xs font-medium text-yellow-400 flex items-center gap-1">
                <AlertTriangle className="h-3.5 w-3.5" /> Skipped entries
              </p>
              {result.warnings.map((w, i) => (
                <p key={i} className="text-xs text-gray-500 ml-5">
                  <span className="font-mono text-gray-400">{w.mitre_id}</span>: {w.reason}
                </p>
              ))}
            </div>
          )}
        </div>
      )}

      {importMutation.isError && (
        <div className="flex items-start gap-2 rounded-xl border border-red-500/30 bg-red-900/20 p-4 text-sm text-red-400">
          <XCircle className="h-4 w-4 mt-0.5 shrink-0" />
          {(importMutation.error as Error)?.message || "Import failed"}
        </div>
      )}

      {/* ── Base64 Image Converter ─────────────────────────────────── */}
      <Base64Converter />
    </div>
  );
}

/* ── Base64 Converter Component ────────────────────────────────────── */

interface ConvertedImage {
  id: string;
  filename: string;
  dataUrl: string;   // data:image/xxx;base64,... — used for <img> preview
  b64: string;       // raw base64 data — used in the JSON evidence field
  sizeKb: number;
}

function Base64Converter() {
  const [images, setImages] = useState<ConvertedImage[]>([]);
  const [dragging, setDragging] = useState(false);
  const [copiedId, setCopiedId] = useState<string | null>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  const processFiles = useCallback((files: FileList | File[]) => {
    const fileArr = Array.from(files);
    const allowed = ["image/png", "image/jpeg", "image/gif", "image/webp", "image/bmp"];
    fileArr.forEach((file) => {
      if (!allowed.includes(file.type)) return;
      const reader = new FileReader();
      reader.onload = (e) => {
        const dataUrl = e.target?.result as string;
        // dataUrl = "data:image/png;base64,iVBORw..."
        const b64 = dataUrl.split(",")[1] ?? "";
        setImages((prev) => [
          ...prev,
          {
            id: crypto.randomUUID(),
            filename: file.name,
            dataUrl,
            b64,
            sizeKb: Math.round(file.size / 1024),
          },
        ]);
      };
      reader.readAsDataURL(file);
    });
  }, []);

  const handleDrop = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault();
      setDragging(false);
      if (e.dataTransfer.files.length) processFiles(e.dataTransfer.files);
    },
    [processFiles],
  );

  const copyToClipboard = (text: string, id: string) => {
    navigator.clipboard.writeText(text).then(() => {
      setCopiedId(id);
      setTimeout(() => setCopiedId(null), 2000);
    });
  };

  const jsonSnippet = (img: ConvertedImage) =>
    JSON.stringify({ filename: img.filename, data: img.b64, caption: "" }, null, 2);

  return (
    <div className="rounded-xl border border-purple-500/20 bg-gray-900 p-5 space-y-4">
      {/* Header */}
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-2">
          <div className="rounded-lg bg-purple-500/10 p-1.5">
            <ImageIcon className="h-4 w-4 text-purple-400" />
          </div>
          <div>
            <h2 className="text-sm font-semibold text-white">Image → Base64 Converter</h2>
            <p className="text-xs text-gray-500">
              Drop screenshots here to get their base64 — paste directly into your JSON
            </p>
          </div>
        </div>
        {images.length > 0 && (
          <button
            onClick={() => setImages([])}
            className="flex items-center gap-1.5 rounded-lg border border-gray-700 px-2.5 py-1.5 text-xs text-gray-400 hover:border-red-500/40 hover:text-red-400 transition-colors"
          >
            <Trash2 className="h-3 w-3" />
            Clear all
          </button>
        )}
      </div>

      {/* Drop zone */}
      <div
        onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
        onDragLeave={() => setDragging(false)}
        onDrop={handleDrop}
        onClick={() => inputRef.current?.click()}
        className={`flex cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border-2 border-dashed py-8 transition-colors ${
          dragging
            ? "border-purple-400 bg-purple-500/10"
            : "border-gray-700 hover:border-purple-500/50 hover:bg-purple-500/5"
        }`}
      >
        <Upload className={`h-6 w-6 transition-colors ${dragging ? "text-purple-400" : "text-gray-600"}`} />
        <p className="text-sm text-gray-500">
          <span className="font-medium text-purple-400">Click or drag</span> images here
        </p>
        <p className="text-xs text-gray-600">PNG · JPG · GIF · WebP · BMP</p>
        <input
          ref={inputRef}
          type="file"
          accept="image/png,image/jpeg,image/gif,image/webp,image/bmp"
          multiple
          className="hidden"
          onChange={(e) => { if (e.target.files) { processFiles(e.target.files); e.target.value = ""; } }}
        />
      </div>

      {/* Converted images */}
      {images.length > 0 && (
        <div className="space-y-3">
          {images.map((img) => (
            <div key={img.id} className="flex gap-3 rounded-xl border border-gray-800 bg-gray-800/40 p-3">
              {/* Thumbnail */}
              <img
                src={img.dataUrl}
                alt={img.filename}
                className="h-20 w-20 shrink-0 rounded-lg border border-gray-700 object-cover"
              />

              {/* Info + actions */}
              <div className="flex flex-1 flex-col gap-2 min-w-0">
                <div className="flex items-center justify-between gap-2">
                  <p className="truncate text-sm font-medium text-gray-200">{img.filename}</p>
                  <span className="shrink-0 text-xs text-gray-500">{img.sizeKb} KB</span>
                </div>

                {/* base64 preview (truncated) */}
                <div className="rounded-lg border border-gray-700 bg-gray-900 px-3 py-1.5">
                  <p className="truncate font-mono text-xs text-gray-500">
                    {img.b64.slice(0, 80)}…
                  </p>
                </div>

                {/* Copy buttons */}
                <div className="flex gap-2">
                  <button
                    onClick={() => copyToClipboard(img.b64, `b64-${img.id}`)}
                    className="flex items-center gap-1.5 rounded-lg border border-gray-700 bg-gray-800 px-3 py-1.5 text-xs font-medium text-gray-300 hover:border-cyan-500/40 hover:text-cyan-400 transition-colors"
                  >
                    {copiedId === `b64-${img.id}` ? (
                      <><Check className="h-3 w-3 text-green-400" /><span className="text-green-400">Copied!</span></>
                    ) : (
                      <><Copy className="h-3 w-3" />Copy base64</>
                    )}
                  </button>

                  <button
                    onClick={() => copyToClipboard(jsonSnippet(img), `json-${img.id}`)}
                    className="flex items-center gap-1.5 rounded-lg border border-gray-700 bg-gray-800 px-3 py-1.5 text-xs font-medium text-gray-300 hover:border-purple-500/40 hover:text-purple-400 transition-colors"
                  >
                    {copiedId === `json-${img.id}` ? (
                      <><Check className="h-3 w-3 text-green-400" /><span className="text-green-400">Copied!</span></>
                    ) : (
                      <><Braces className="h-3 w-3" />Copy JSON snippet</>
                    )}
                  </button>

                  <button
                    onClick={() => setImages((prev) => prev.filter((im) => im.id !== img.id))}
                    className="ml-auto rounded-lg border border-gray-700 p-1.5 text-gray-600 hover:border-red-500/40 hover:text-red-400 transition-colors"
                  >
                    <Trash2 className="h-3 w-3" />
                  </button>
                </div>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
