import L from "leaflet";
import "leaflet/dist/leaflet.css";
import { Download, Loader2, MapPin } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { CollapsibleSection } from "@/components/common/collapsible-section";
import { MetadataGrid } from "@/components/common/metadata-grid";
import { ProgressCard } from "@/components/common/progress-card";
import { useToolProcessor } from "@/hooks/use-tool-processor";
import { formatHeaders } from "@/lib/api";
import { EXIF_LABELS, SKIP_KEYS } from "@/lib/metadata-utils";
import { useFileStore } from "@/stores/file-store";

/** Interactive Leaflet map with a red circle marker. */
function MiniMap({ lat, lon, zoom = 15 }: { lat: number; lon: number; zoom?: number }) {
  const containerRef = useRef<HTMLDivElement>(null);
  const mapRef = useRef<L.Map | null>(null);

  useEffect(() => {
    if (!containerRef.current || mapRef.current) return;

    const map = L.map(containerRef.current, {
      zoomControl: false,
      attributionControl: false,
    }).setView([lat, lon], zoom);

    L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
      maxZoom: 19,
    }).addTo(map);

    L.circleMarker([lat, lon], {
      radius: 7,
      color: "#fff",
      weight: 2,
      fillColor: "#ef4444",
      fillOpacity: 1,
    }).addTo(map);

    mapRef.current = map;

    return () => {
      map.remove();
      mapRef.current = null;
    };
  }, [lat, lon, zoom]);

  return (
    <div
      ref={containerRef}
      className="w-full h-36 rounded-md overflow-hidden border border-border"
    />
  );
}

interface MetadataResult {
  filename: string;
  fileSize: number;
  exif?: Record<string, unknown> | null;
  exifError?: string;
  gps?: Record<string, unknown> | null;
  icc?: Record<string, string> | null;
  xmp?: Record<string, string> | null;
}

interface StripMetadataControlsProps {
  settings?: Record<string, unknown>;
  onChange?: (settings: Record<string, unknown>) => void;
  /** Passed from parent to preserve field-count badges in checkbox labels */
  metadata?: MetadataResult | null;
  hasExif?: boolean;
  hasGps?: boolean;
}

export function StripMetadataControls({
  settings: initialSettings,
  onChange,
  metadata,
  hasExif,
  hasGps,
}: StripMetadataControlsProps) {
  const [stripAll, setStripAll] = useState(true);
  const [stripExif, setStripExif] = useState(false);
  const [stripGps, setStripGps] = useState(false);
  const [stripIcc, setStripIcc] = useState(false);
  const [stripXmp, setStripXmp] = useState(false);

  const initializedRef = useRef(false);
  useEffect(() => {
    if (!initialSettings || initializedRef.current) return;
    initializedRef.current = true;
    if (initialSettings.stripAll != null) setStripAll(Boolean(initialSettings.stripAll));
    if (initialSettings.stripExif != null) setStripExif(Boolean(initialSettings.stripExif));
    if (initialSettings.stripGps != null) setStripGps(Boolean(initialSettings.stripGps));
    if (initialSettings.stripIcc != null) setStripIcc(Boolean(initialSettings.stripIcc));
    if (initialSettings.stripXmp != null) setStripXmp(Boolean(initialSettings.stripXmp));
  }, [initialSettings]);

  const onChangeRef = useRef(onChange);
  onChangeRef.current = onChange;

  // Report settings on change
  useEffect(() => {
    onChangeRef.current?.({ stripAll, stripExif, stripGps, stripIcc, stripXmp });
  }, [stripAll, stripExif, stripGps, stripIcc, stripXmp]);

  const handleStripAllChange = (checked: boolean) => {
    setStripAll(checked);
    if (checked) {
      setStripExif(false);
      setStripGps(false);
      setStripIcc(false);
      setStripXmp(false);
    }
  };

  return (
    <>
      {/* Remove All */}
      <label className="flex items-center gap-2 text-sm text-foreground font-medium">
        <input
          type="checkbox"
          checked={stripAll}
          onChange={(e) => handleStripAllChange(e.target.checked)}
          className="rounded"
        />
        Remove All Metadata
      </label>

      <div className="border-t border-border" />

      {/* Individual options */}
      <div className="space-y-2">
        <p className="text-xs text-muted-foreground">Or select specific metadata:</p>

        <label
          className={`flex items-center gap-2 text-sm ${stripAll ? "text-muted-foreground" : "text-foreground"}`}
        >
          <input
            type="checkbox"
            checked={stripExif}
            onChange={(e) => setStripExif(e.target.checked)}
            disabled={stripAll}
            className="rounded"
          />
          Strip EXIF (camera info, date, exposure)
          {hasExif && !stripAll && (
            <span className="ms-auto text-[10px] text-muted-foreground">
              {Object.keys(metadata?.exif ?? {}).filter((k) => !SKIP_KEYS.has(k)).length} fields
            </span>
          )}
        </label>

        <label
          className={`flex items-center gap-2 text-sm ${stripAll ? "text-muted-foreground" : "text-foreground"}`}
        >
          <input
            type="checkbox"
            checked={stripGps}
            onChange={(e) => setStripGps(e.target.checked)}
            disabled={stripAll}
            className="rounded"
          />
          Strip GPS (location data)
          {hasGps && !stripAll && (
            <span className="ms-auto text-[10px] text-amber-500">location found</span>
          )}
        </label>

        <label
          className={`flex items-center gap-2 text-sm ${stripAll ? "text-muted-foreground" : "text-foreground"}`}
        >
          <input
            type="checkbox"
            checked={stripIcc}
            onChange={(e) => setStripIcc(e.target.checked)}
            disabled={stripAll}
            className="rounded"
          />
          Strip ICC (color profile)
        </label>

        <label
          className={`flex items-center gap-2 text-sm ${stripAll ? "text-muted-foreground" : "text-foreground"}`}
        >
          <input
            type="checkbox"
            checked={stripXmp}
            onChange={(e) => setStripXmp(e.target.checked)}
            disabled={stripAll}
            className="rounded"
          />
          Strip XMP (extensible metadata)
        </label>
      </div>
    </>
  );
}

export function StripMetadataSettings() {
  const { entries, selectedIndex, files } = useFileStore();
  const {
    processFiles,
    processAllFiles,
    processing,
    error,
    downloadUrl,
    originalSize,
    processedSize,
    progress,
  } = useToolProcessor("strip-metadata");

  const [stripSettings, setStripSettings] = useState<Record<string, unknown>>({
    stripAll: true,
    stripExif: false,
    stripGps: false,
    stripIcc: false,
    stripXmp: false,
  });

  // Per-file metadata cache (from feature branch)
  const [metadataCache, setMetadataCache] = useState<Map<string, MetadataResult>>(new Map());
  const [metadata, setMetadata] = useState<MetadataResult | null>(null);
  const [inspecting, setInspecting] = useState(false);
  const [inspectError, setInspectError] = useState<string | null>(null);

  const currentFile = entries[selectedIndex]?.file ?? null;
  const fileKey = currentFile
    ? `${currentFile.name}-${currentFile.size}-${currentFile.lastModified}`
    : null;

  // Auto-fetch metadata for the selected file (with per-file caching)
  useEffect(() => {
    if (!currentFile || !fileKey) {
      setMetadata(null);
      setInspectError(null);
      return;
    }

    // Check cache first
    const cached = metadataCache.get(fileKey);
    if (cached) {
      setMetadata(cached);
      return;
    }

    const controller = new AbortController();
    (async () => {
      setInspecting(true);
      setInspectError(null);
      setMetadata(null);
      try {
        const formData = new FormData();
        formData.append("file", currentFile);
        const res = await fetch("/api/v1/tools/image/strip-metadata/inspect", {
          method: "POST",
          headers: formatHeaders(),
          body: formData,
          signal: controller.signal,
        });
        if (!res.ok) {
          const body = await res.json().catch(() => ({}));
          throw new Error(body.error || `Failed: ${res.status}`);
        }
        const data: MetadataResult = await res.json();
        setMetadata(data);
        if (fileKey) setMetadataCache((prev) => new Map(prev).set(fileKey, data));
      } catch (err) {
        if ((err as Error).name === "AbortError") return;
        setInspectError(err instanceof Error ? err.message : "Failed to inspect metadata");
      } finally {
        setInspecting(false);
      }
    })();

    return () => controller.abort();
  }, [currentFile, fileKey, metadataCache]);

  const handleProcess = () => {
    if (files.length > 1) {
      processAllFiles(files, stripSettings);
    } else {
      processFiles(files, stripSettings);
    }
  };

  const hasFile = files.length > 0;

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (hasFile && !processing) handleProcess();
  };

  const hasExif = metadata?.exif && Object.keys(metadata.exif).length > 0;
  const hasGps = metadata?.gps && Object.keys(metadata.gps).length > 0;
  const hasIcc = metadata?.icc && Object.keys(metadata.icc).length > 0;
  const hasXmp = metadata?.xmp && Object.keys(metadata.xmp).length > 0;
  const hasAnyMetadata = hasExif || hasGps || hasIcc || hasXmp;
  const sectionCount = [hasExif, hasGps, hasIcc, hasXmp].filter(Boolean).length;

  // GPS coordinates for display
  const gpsLat = metadata?.gps?._latitude as number | null | undefined;
  const gpsLon = metadata?.gps?._longitude as number | null | undefined;

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      {/* Metadata Display */}
      {hasFile && (
        <div className="space-y-2">
          <p className="text-xs font-medium text-muted-foreground">Current Metadata</p>

          {inspecting && (
            <div className="flex items-center gap-2 text-xs text-muted-foreground py-2">
              <Loader2 className="h-3 w-3 animate-spin" />
              Reading metadata...
            </div>
          )}

          {inspectError && <p className="text-[10px] text-red-500">{inspectError}</p>}

          {metadata && !hasAnyMetadata && !inspecting && (
            <p className="text-xs text-muted-foreground italic py-1">
              No metadata found in this image.
            </p>
          )}

          {metadata && hasAnyMetadata && (
            <div className="space-y-1.5">
              {/* GPS warning banner + map */}
              {hasGps && gpsLat != null && gpsLon != null && (
                <div className="space-y-2">
                  <div className="flex items-center gap-2 px-2.5 py-1.5 rounded-md bg-amber-500/10 border border-amber-500/20">
                    <MapPin className="h-3 w-3 text-amber-500 shrink-0" />
                    <span className="text-[10px] text-amber-600 dark:text-amber-400 font-medium">
                      Location data: {gpsLat.toFixed(6)}, {gpsLon.toFixed(6)}
                    </span>
                  </div>
                  <MiniMap lat={gpsLat} lon={gpsLon} />
                  <p className="text-[10px] text-amber-600 dark:text-amber-400">
                    This image contains your precise location. Consider removing GPS data before
                    sharing.
                  </p>
                </div>
              )}

              {hasExif && metadata.exif && (
                <CollapsibleSection
                  title="EXIF"
                  badge={`${Object.keys(metadata.exif).filter((k) => !SKIP_KEYS.has(k) && !k.startsWith("_")).length} fields`}
                  defaultOpen
                >
                  <MetadataGrid data={metadata.exif} labelMap={EXIF_LABELS} />
                </CollapsibleSection>
              )}

              {metadata?.exifError && (
                <p className="text-[11px] text-muted-foreground">EXIF: {metadata.exifError}</p>
              )}

              {hasGps && metadata.gps && (
                <CollapsibleSection
                  title="GPS"
                  warning
                  badge={`${Object.keys(metadata.gps).filter((k) => !k.startsWith("_")).length} fields`}
                >
                  <MetadataGrid data={metadata.gps} />
                </CollapsibleSection>
              )}

              {hasIcc && metadata.icc && (
                <CollapsibleSection
                  title="ICC Profile"
                  badge={`${Object.keys(metadata.icc).length} fields`}
                >
                  <MetadataGrid data={metadata.icc} />
                </CollapsibleSection>
              )}

              {hasXmp && metadata.xmp && (
                <CollapsibleSection
                  title="XMP"
                  badge={`${Object.keys(metadata.xmp).length} fields`}
                >
                  <MetadataGrid data={metadata.xmp} />
                </CollapsibleSection>
              )}

              <p className="text-[10px] text-muted-foreground">
                {sectionCount} metadata {sectionCount === 1 ? "section" : "sections"} found
              </p>
            </div>
          )}
        </div>
      )}

      {hasFile && hasAnyMetadata && <div className="border-t border-border" />}

      <StripMetadataControls
        onChange={setStripSettings}
        metadata={metadata}
        hasExif={!!hasExif}
        hasGps={!!hasGps}
      />

      {/* Error */}
      {error && <p className="text-xs text-red-500">{error}</p>}

      {/* Size info */}
      {originalSize != null && processedSize != null && (
        <div className="text-xs text-muted-foreground space-y-0.5">
          <p>Original: {(originalSize / 1024).toFixed(1)} KB</p>
          <p>Processed: {(processedSize / 1024).toFixed(1)} KB</p>
          <p>Metadata removed: {((originalSize - processedSize) / 1024).toFixed(1)} KB</p>
        </div>
      )}

      {/* Process */}
      {processing ? (
        <ProgressCard
          active={processing}
          phase={progress.phase === "idle" ? "uploading" : progress.phase}
          label="Removing metadata"
          stage={progress.stage}
          percent={progress.percent}
          elapsed={progress.elapsed}
        />
      ) : (
        <button
          type="submit"
          data-testid="strip-metadata-submit"
          disabled={!hasFile || processing}
          className="w-full py-2.5 rounded-lg bg-primary text-primary-foreground font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
        >
          Remove Metadata
        </button>
      )}

      {/* Download */}
      {downloadUrl && (
        <a
          href={downloadUrl}
          download
          data-testid="strip-metadata-download"
          className="w-full py-2.5 rounded-lg border border-primary text-primary font-medium flex items-center justify-center gap-2 hover:bg-primary/5"
        >
          <Download className="h-4 w-4" />
          Download
        </a>
      )}
    </form>
  );
}
