﻿import { useEffect, useMemo, useRef, useState } from "react";

type JobStatus = "queued" | "running" | "done" | "error" | "cancelled";

type ModelInfo = {
  id: string;
  name: string;
  available: boolean;
  description: string;
};

type JobInfo = {
  job_id: string;
  status: JobStatus;
  progress: number;
  message: string;
  image_paths: string[];
  output_dir: string | null;
  error: string | null;
};

type HistoryItem = {
  prompt: string;
  negative_prompt: string;
  timestamp: string;
};

type Preset = {
  name: string;
  prompt: string;
  negative_prompt: string;
  model: string;
  size: string;
  count: number;
  steps: number;
  guidance: number;
  image_type: string;
  style_preset: string;
  style_strength: number;
  updated_at: string;
};

type DashboardStats = {
  queued: number;
  running: number;
  done: number;
  error: number;
  cancelled: number;
  total: number;
  last_24h: number;
};

type AdminSettings = {
  content_profile: string;
  rate_limit_per_minute: number;
  output_retention_days: number;
  adult_enabled: boolean;
};

const API_BASE = "http://127.0.0.1:8008";

function toImageUrl(path: string): string {
  return `${API_BASE}/image?path=${encodeURIComponent(path)}`;
}

type ResolvedImageProps = {
  path: string;
  alt: string;
};

function ResolvedImage({ path, alt }: ResolvedImageProps) {
  const [src, setSrc] = useState(() => toImageUrl(path));

  useEffect(() => {
    let active = true;
    setSrc(toImageUrl(path));
    void window.imageForge.readImageDataUrl(path).then((dataUrl) => {
      if (active && dataUrl) {
        setSrc(dataUrl);
      }
    });
    return () => {
      active = false;
    };
  }, [path]);

  return <img src={src} alt={alt} />;
}

async function api<T>(path: string, init?: RequestInit): Promise<T> {
  const apiKey = localStorage.getItem("imageforge_api_key") || "";
  const response = await fetch(`${API_BASE}${path}`, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      "X-ImageForge-Api-Key": apiKey,
      ...(init?.headers || {}),
    },
  });
  if (!response.ok) {
    const text = await response.text();
    throw new Error(text || `HTTP ${response.status}`);
  }
  return (await response.json()) as T;
}

function App() {
  const [activeTab, setActiveTab] = useState<"studio" | "dashboard" | "presets" | "settings">("studio");
  const [apiKeyInput, setApiKeyInput] = useState(localStorage.getItem("imageforge_api_key") || "");
  const [adminSettings, setAdminSettings] = useState<AdminSettings | null>(null);
  const lastJobLogSignatureRef = useRef<string>("");
  const [models, setModels] = useState<ModelInfo[]>([]);
  const [history, setHistory] = useState<HistoryItem[]>([]);
  const [presets, setPresets] = useState<Preset[]>([]);
  const [stats, setStats] = useState<DashboardStats | null>(null);

  const [prompt, setPrompt] = useState("");
  const [batchPrompts, setBatchPrompts] = useState("");
  const [negativePrompt, setNegativePrompt] = useState("");
  const [model, setModel] = useState("dummy");
  const [modelVariant, setModelVariant] = useState("");
  const [size, setSize] = useState("512x512");
  const [count, setCount] = useState(1);
  const [randomSeed, setRandomSeed] = useState(true);
  const [seed, setSeed] = useState<number>(42);
  const [steps, setSteps] = useState(18);
  const [guidance, setGuidance] = useState(6.5);
  const [imageType, setImageType] = useState("general");
  const [stylePreset, setStylePreset] = useState("auto");
  const [styleStrength, setStyleStrength] = useState(60);
  const [initImagePath, setInitImagePath] = useState<string | null>(null);
  const [img2imgStrength, setImg2imgStrength] = useState(0.45);

  const [currentJobId, setCurrentJobId] = useState<string | null>(null);
  const [jobs, setJobs] = useState<JobInfo[]>([]);
  const [jobInfo, setJobInfo] = useState<JobInfo | null>(null);
  const [logs, setLogs] = useState<string[]>([]);
  const [selectedImage, setSelectedImage] = useState<string | null>(null);
  const [compareImages, setCompareImages] = useState<string[]>([]);

  async function refreshModels() {
    const response = await api<{ value: ModelInfo[]; Count: number }>("/models");
    const data = Array.isArray(response) ? response : response.value || [];
    setModels(data);
    const preferred = ["a1111", "localai", "diffusion", "dummy"];
    const available =
      preferred
        .map((id) => data.find((m) => m.id === id && m.available))
        .find(Boolean) ||
      data.find((m) => m.available) ||
      data[0];
    if (available) {
      setModel((prev) => {
        const current = data.find((m) => m.id === prev);
        if (!current || !current.available || prev === "dummy") {
          return available.id;
        }
        return prev;
      });
    }
  }

  async function refreshHistory() {
    const data = await api<HistoryItem[]>("/history");
    setHistory(data);
  }

  async function refreshJobs() {
    const data = await api<JobInfo[]>("/jobs");
    setJobs(data);
  }

  async function refreshPresets() {
    const data = await api<Preset[]>("/presets");
    setPresets(data);
  }

  async function refreshStats() {
    const data = await api<DashboardStats>("/dashboard/stats");
    setStats(data);
  }

  async function refreshAdminSettings() {
    try {
      const data = await api<AdminSettings>("/admin/settings");
      setAdminSettings(data);
    } catch {
      setAdminSettings(null);
    }
  }

  useEffect(() => {
    void Promise.all([refreshModels(), refreshHistory(), refreshJobs(), refreshPresets(), refreshStats(), refreshAdminSettings()]).catch((err: Error) => {
      void window.imageForge.showError("Startup Error", err.message);
    });
  }, []);

  useEffect(() => {
    const timer = window.setInterval(() => {
      void refreshJobs().catch(() => {});
      void refreshStats().catch(() => {});
    }, 2000);
    return () => window.clearInterval(timer);
  }, []);

  useEffect(() => {
    if (!currentJobId) {
      return;
    }
    const timer = window.setInterval(() => {
      void api<JobInfo>(`/jobs/${currentJobId}`)
        .then((info) => {
          setJobInfo(info);
          const signature = `${info.status}|${info.progress}|${info.message}`;
          if (lastJobLogSignatureRef.current !== signature) {
            lastJobLogSignatureRef.current = signature;
            setLogs((prev) => {
              const next = [...prev, `${new Date().toLocaleTimeString()} | ${info.message}`];
              return next.slice(-200);
            });
          }
          if (info.status === "done") {
            setSelectedImage(info.image_paths[0] || null);
            setCurrentJobId(null);
            void refreshHistory().catch(() => {});
            void refreshJobs().catch(() => {});
          }
          if (info.status === "error" || info.status === "cancelled") {
            setCurrentJobId(null);
            if (info.error) {
              void window.imageForge.showError("Generation Error", info.error);
            }
          }
        })
        .catch((err: Error) => {
          setLogs((prev) => [...prev, `${new Date().toLocaleTimeString()} | Poll failed: ${err.message}`]);
        });
    }, 1000);

    return () => window.clearInterval(timer);
  }, [currentJobId]);

  const isGenerating = useMemo(
    () => Boolean(currentJobId) || jobInfo?.status === "queued" || jobInfo?.status === "running",
    [currentJobId, jobInfo?.status]
  );

  function buildPayload(basePrompt: string) {
    return {
      prompt: basePrompt,
      negative_prompt: negativePrompt,
      model,
      model_variant: modelVariant.trim() || null,
      size,
      count,
      random_seed: randomSeed,
      seed: randomSeed ? null : seed,
      steps,
      guidance,
      image_type: imageType,
      style_preset: stylePreset,
      style_strength: styleStrength,
      init_image_path: initImagePath,
      img2img_strength: img2imgStrength,
    };
  }

  async function submitOne(basePrompt: string) {
    const response = await api<{ job_id: string }>("/generate", {
      method: "POST",
      body: JSON.stringify(buildPayload(basePrompt)),
    });
    return response.job_id;
  }

  async function handleGenerate() {
    if (!prompt.trim()) {
      await window.imageForge.showError("Validation", "Prompt darf nicht leer sein.");
      return;
    }
    try {
      setLogs((prev) => [...prev, `${new Date().toLocaleTimeString()} | Submit generation`]);
      setJobInfo(null);
      lastJobLogSignatureRef.current = "";
      setSelectedImage(null);
      const jobId = await submitOne(prompt.trim());
      setCurrentJobId(jobId);
      await refreshJobs();
    } catch (err) {
      const message = err instanceof Error ? err.message : String(err);
      await window.imageForge.showError("Generate Failed", message);
    }
  }

  async function handleBatchGenerate() {
    const lines = batchPrompts
      .split("\n")
      .map((line) => line.trim())
      .filter(Boolean);
    if (lines.length === 0) {
      await window.imageForge.showError("Validation", "Batch-Prompts sind leer.");
      return;
    }
    try {
      for (const line of lines) {
        await submitOne(line);
      }
      setLogs((prev) => [...prev, `${new Date().toLocaleTimeString()} | Batch queued (${lines.length})`]);
      await refreshJobs();
      await refreshStats();
    } catch (err) {
      const message = err instanceof Error ? err.message : String(err);
      await window.imageForge.showError("Batch Failed", message);
    }
  }

  async function handleCancel() {
    if (!currentJobId) {
      return;
    }
    await api(`/jobs/${currentJobId}/cancel`, { method: "POST" });
    setLogs((prev) => [...prev, `${new Date().toLocaleTimeString()} | Cancel requested`]);
    await refreshJobs();
  }

  async function handleCancelById(jobId: string) {
    await api(`/jobs/${jobId}/cancel`, { method: "POST" });
    await refreshJobs();
  }

  async function handleRetry(jobId: string) {
    const out = await api<{ new_job_id: string }>(`/jobs/${jobId}/retry`, { method: "POST" });
    setCurrentJobId(out.new_job_id);
    await refreshJobs();
  }

  async function handleSaveImage() {
    if (!selectedImage) {
      return;
    }
    const ok = await window.imageForge.saveImage(selectedImage, "imageforge_output.png");
    if (ok) {
      setLogs((prev) => [...prev, `${new Date().toLocaleTimeString()} | Image saved`]);
    }
  }

  async function handleExportImage(format: "png" | "jpg" | "webp") {
    if (!selectedImage) {
      return;
    }
    const out = await api<{ output_path: string }>("/export", {
      method: "POST",
      body: JSON.stringify({ source_path: selectedImage, format, quality: 92 }),
    });
    await window.imageForge.saveImage(out.output_path, `imageforge_export.${format}`);
  }

  async function handleOpenFolder() {
    if (jobInfo?.output_dir) {
      await window.imageForge.openFolder(jobInfo.output_dir);
    }
  }

  async function handlePickInitImage() {
    const path = await window.imageForge.pickImage();
    if (path) {
      setInitImagePath(path);
    }
  }

  function toggleCompare(path: string) {
    setCompareImages((prev) => (prev.includes(path) ? prev.filter((p) => p !== path) : [...prev.slice(-3), path]));
  }

  async function savePreset() {
    const name = prompt.slice(0, 40) || `preset-${Date.now()}`;
    const payload = {
      name,
      prompt,
      negative_prompt: negativePrompt,
      model,
      size,
      count,
      steps,
      guidance,
      image_type: imageType,
      style_preset: stylePreset,
      style_strength: styleStrength,
    };
    await api("/presets", { method: "POST", body: JSON.stringify(payload) });
    await refreshPresets();
  }

  function applyHyperrealPortraitPreset() {
    setImageType("portrait");
    setStylePreset("photorealistic");
    setStyleStrength(90);
    setSteps(48);
    setGuidance(7.0);
    setModel((prev) => prev || "localai");
    setNegativePrompt(
      "low quality, blurry, bad anatomy, extra fingers, waxy skin, overprocessed face, watermark"
    );
  }

  function applyHyperrealProductPreset() {
    setImageType("product");
    setStylePreset("photorealistic");
    setStyleStrength(85);
    setSteps(42);
    setGuidance(6.5);
    setModel((prev) => prev || "localai");
    setNegativePrompt(
      "low quality, blurry, noisy, distorted geometry, warped label, watermark, text clutter"
    );
  }

  async function applyPreset(p: Preset) {
    setPrompt(p.prompt);
    setNegativePrompt(p.negative_prompt);
    setModel(p.model);
    setSize(p.size);
    setCount(p.count);
    setSteps(p.steps);
    setGuidance(p.guidance);
    setImageType(p.image_type);
    setStylePreset(p.style_preset);
    setStyleStrength(p.style_strength);
    setActiveTab("studio");
  }

  async function deletePreset(name: string) {
    await api(`/presets/${encodeURIComponent(name)}`, { method: "DELETE" });
    await refreshPresets();
  }

  async function saveAdminSettings() {
    if (!adminSettings) {
      return;
    }
    const out = await api<AdminSettings>("/admin/settings", {
      method: "PUT",
      body: JSON.stringify(adminSettings),
    });
    setAdminSettings(out);
    setLogs((prev) => [...prev, `${new Date().toLocaleTimeString()} | Admin settings updated`]);
  }

  return (
    <div className="app-grid">
      <aside className="sidebar">
        <h2>Control</h2>
        <div className="tabs">
          <button className={activeTab === "studio" ? "tab-active" : ""} onClick={() => setActiveTab("studio")}>Studio</button>
          <button className={activeTab === "dashboard" ? "tab-active" : ""} onClick={() => setActiveTab("dashboard")}>Dashboard</button>
          <button className={activeTab === "presets" ? "tab-active" : ""} onClick={() => setActiveTab("presets")}>Presets</button>
          <button className={activeTab === "settings" ? "tab-active" : ""} onClick={() => setActiveTab("settings")}>Settings</button>
        </div>
        <label>
          API Key
          <div className="row-actions">
            <input value={apiKeyInput} onChange={(e) => setApiKeyInput(e.target.value)} />
            <button
              type="button"
              onClick={() => {
                localStorage.setItem("imageforge_api_key", apiKeyInput.trim());
                void Promise.all([refreshModels(), refreshJobs(), refreshStats()]).catch(() => {});
              }}
            >
              Save
            </button>
          </div>
        </label>

        <label>
          Model
          <select value={model} onChange={(e) => setModel(e.target.value)}>
            {models.map((m) => (
              <option key={m.id} value={m.id} disabled={!m.available}>
                {m.name} {m.available ? "" : "(not available)"}
              </option>
            ))}
          </select>
        </label>
        <label>
          Model Variant / Checkpoint
          <input value={modelVariant} onChange={(e) => setModelVariant(e.target.value)} placeholder="optional model id" />
        </label>
        <label>
          Size
          <select value={size} onChange={(e) => setSize(e.target.value)}>
            <option value="512x512">512x512 (fast)</option>
            <option value="768x768">768x768</option>
            <option value="1024x1024">1024x1024</option>
            <option value="1024x1536">1024x1536</option>
            <option value="1536x1024">1536x1024</option>
          </select>
        </label>
        <label>
          Count
          <input type="number" min={1} max={4} value={count} onChange={(e) => setCount(Number(e.target.value) || 1)} />
        </label>
        <label className="row">
          <input type="checkbox" checked={randomSeed} onChange={(e) => setRandomSeed(e.target.checked)} /> Random Seed
        </label>
        <label>
          Seed
          <input type="number" disabled={randomSeed} value={seed} onChange={(e) => setSeed(Number(e.target.value) || 0)} />
        </label>
        <label>
          Steps / Quality: {steps}
          <input type="range" min={1} max={100} value={steps} onChange={(e) => setSteps(Number(e.target.value))} />
        </label>
        <label>
          Guidance / Creativity: {guidance.toFixed(1)}
          <input type="range" min={1} max={20} step={0.5} value={guidance} onChange={(e) => setGuidance(Number(e.target.value))} />
        </label>
        <label>
          Bildtyp
          <select value={imageType} onChange={(e) => setImageType(e.target.value)}>
            <option value="general">Allgemein</option>
            <option value="photo">Foto</option>
            <option value="portrait">Portrait</option>
            <option value="landscape">Landschaft</option>
            <option value="architecture">Architektur</option>
            <option value="product">Produkt</option>
            <option value="logo">Logo</option>
            <option value="icon">Icon</option>
            <option value="poster">Poster</option>
            <option value="illustration">Illustration</option>
            <option value="anime">Anime</option>
            <option value="pixel_art">Pixel Art</option>
            <option value="sketch">Skizze</option>
            <option value="painting">Painting</option>
            <option value="3d">3D Render</option>
          </select>
        </label>
        <label>
          Stil
          <select value={stylePreset} onChange={(e) => setStylePreset(e.target.value)}>
            <option value="auto">Auto</option>
            <option value="photorealistic">Photorealistisch</option>
            <option value="cinematic">Cinematic</option>
            <option value="minimal">Minimal</option>
            <option value="vibrant">Vibrant</option>
            <option value="monochrome">Monochrom</option>
            <option value="watercolor">Watercolor</option>
            <option value="oil">Oil Painting</option>
            <option value="noir">Noir</option>
            <option value="fantasy">Fantasy</option>
          </select>
        </label>
        <label>
          Stil-Staerke: {styleStrength}%
          <input type="range" min={0} max={100} step={5} value={styleStrength} onChange={(e) => setStyleStrength(Number(e.target.value))} />
        </label>
        <label>
          Input-Bild (Img2Img)
          <div className="row-actions">
            <button type="button" onClick={handlePickInitImage}>Bild waehlen</button>
            <button type="button" onClick={() => setInitImagePath(null)} disabled={!initImagePath}>Entfernen</button>
          </div>
          {initImagePath ? <small>{initImagePath}</small> : <small>Kein Startbild gesetzt</small>}
        </label>
        <label>
          Img2Img Staerke: {img2imgStrength.toFixed(2)}
          <input type="range" min={0} max={1} step={0.05} value={img2imgStrength} onChange={(e) => setImg2imgStrength(Number(e.target.value))} disabled={!initImagePath} />
        </label>
      </aside>

      <main className="main-area">
        {activeTab === "studio" && (
          <>
            <h1>ImageForge Studio</h1>
            <label>
              Prompt
              <textarea value={prompt} onChange={(e) => setPrompt(e.target.value)} rows={5} placeholder="Describe your image..." />
            </label>
            <label>
              Negative Prompt
              <textarea value={negativePrompt} onChange={(e) => setNegativePrompt(e.target.value)} rows={3} />
            </label>
            <div className="history-box">
              {history.slice(0, 6).map((item, idx) => (
                <button key={idx} className="history-item" onClick={() => setPrompt(item.prompt)}>
                  {item.prompt}
                </button>
              ))}
            </div>

            <label>
              Batch Queue (ein Prompt pro Zeile)
              <textarea value={batchPrompts} onChange={(e) => setBatchPrompts(e.target.value)} rows={4} placeholder="prompt 1&#10;prompt 2" />
            </label>

            <div className="actions">
              <button onClick={handleGenerate} disabled={isGenerating}>Generate</button>
              <button onClick={handleBatchGenerate}>Queue Batch</button>
              <button onClick={handleCancel} disabled={!isGenerating}>Cancel</button>
              <button onClick={applyHyperrealPortraitPreset}>Hyperreal Portrait</button>
              <button onClick={applyHyperrealProductPreset}>Hyperreal Product</button>
              <button onClick={savePreset}>Save Preset</button>
              <button onClick={handleSaveImage} disabled={!selectedImage}>Save As</button>
              <button onClick={handleOpenFolder} disabled={!jobInfo?.output_dir}>Open Folder</button>
              <button onClick={() => void handleExportImage("webp")} disabled={!selectedImage}>Export WEBP</button>
            </div>
          </>
        )}

        {activeTab === "dashboard" && (
          <>
            <h1>Operations Dashboard</h1>
            {adminSettings && (
              <div className="preset-list" style={{ marginBottom: 12 }}>
                <label className="row" style={{ justifyContent: "space-between" }}>
                  <span>Adult Repo (HF Space) aktivieren</span>
                  <input
                    type="checkbox"
                    checked={adminSettings.adult_enabled}
                    onChange={(e) =>
                      setAdminSettings({ ...adminSettings, adult_enabled: e.target.checked })
                    }
                  />
                </label>
                <div className="row-actions">
                  <button onClick={() => void saveAdminSettings()}>Schalter speichern</button>
                </div>
              </div>
            )}
            <div className="stats-grid">
              <div className="stat-card"><strong>Total</strong><span>{stats?.total ?? 0}</span></div>
              <div className="stat-card"><strong>Queued</strong><span>{stats?.queued ?? 0}</span></div>
              <div className="stat-card"><strong>Running</strong><span>{stats?.running ?? 0}</span></div>
              <div className="stat-card"><strong>Done</strong><span>{stats?.done ?? 0}</span></div>
              <div className="stat-card"><strong>Error</strong><span>{stats?.error ?? 0}</span></div>
              <div className="stat-card"><strong>24h</strong><span>{stats?.last_24h ?? 0}</span></div>
            </div>
            <div className="job-table">
              {jobs.slice(0, 30).map((j) => (
                <div className="job-row" key={j.job_id}>
                  <div>{j.job_id}</div>
                  <div>{j.status}</div>
                  <div>{j.progress}%</div>
                  <div>{j.message}</div>
                  <div className="row-actions">
                    <button onClick={() => void handleRetry(j.job_id)}>Retry</button>
                    <button onClick={() => void handleCancelById(j.job_id)}>Cancel</button>
                  </div>
                </div>
              ))}
            </div>
          </>
        )}

        {activeTab === "presets" && (
          <>
            <h1>Preset Library</h1>
            <div className="preset-list">
              {presets.map((preset) => (
                <div className="preset-item" key={preset.name}>
                  <div>
                    <strong>{preset.name}</strong>
                    <div>{preset.model} | {preset.size} | steps {preset.steps}</div>
                  </div>
                  <div className="row-actions">
                    <button onClick={() => void applyPreset(preset)}>Apply</button>
                    <button onClick={() => void deletePreset(preset.name)}>Delete</button>
                  </div>
                </div>
              ))}
            </div>
          </>
        )}

        {activeTab === "settings" && (
          <>
            <h1>Admin Settings</h1>
            {adminSettings ? (
              <div className="preset-list">
                <label>
                  Content Profile
                  <select
                    value={adminSettings.content_profile}
                    onChange={(e) => setAdminSettings({ ...adminSettings, content_profile: e.target.value })}
                  >
                    <option value="strict">strict</option>
                    <option value="internal-relaxed">internal-relaxed</option>
                  </select>
                </label>
                <label>
                  Rate Limit / min
                  <input
                    type="number"
                    value={adminSettings.rate_limit_per_minute}
                    onChange={(e) =>
                      setAdminSettings({ ...adminSettings, rate_limit_per_minute: Number(e.target.value) || 1 })
                    }
                  />
                </label>
                <label>
                  Output Retention Days
                  <input
                    type="number"
                    value={adminSettings.output_retention_days}
                    onChange={(e) =>
                      setAdminSettings({ ...adminSettings, output_retention_days: Number(e.target.value) || 1 })
                    }
                  />
                </label>
                <label className="row" style={{ justifyContent: "space-between" }}>
                  <span>Adult Repo (HF Space) aktiv</span>
                  <input
                    type="checkbox"
                    checked={adminSettings.adult_enabled}
                    onChange={(e) => setAdminSettings({ ...adminSettings, adult_enabled: e.target.checked })}
                  />
                </label>
                <div className="row-actions">
                  <button onClick={() => void saveAdminSettings()}>Save Settings</button>
                  <button onClick={() => void api("/admin/cleanup", { method: "POST" }).then(refreshStats)}>Run Cleanup</button>
                </div>
              </div>
            ) : (
              <div>No admin permissions for settings.</div>
            )}
          </>
        )}

        <section className="progress-box">
          <div className="progress-label">
            <span>{jobInfo?.status ?? "idle"}</span>
            <span>{jobInfo?.progress ?? 0}%</span>
          </div>
          <progress max={100} value={jobInfo?.progress ?? 0}></progress>
          <div className="log-box">
            {logs.map((line, idx) => (
              <div key={idx}>{line}</div>
            ))}
          </div>
        </section>
      </main>

      <section className="gallery">
        <h2>Gallery & Compare</h2>
        <div className="thumbs">
          {(jobInfo?.image_paths || []).map((path) => (
            <div key={path}>
              <button className="thumb" onClick={() => setSelectedImage(path)}>
                <ResolvedImage path={path} alt="result" />
              </button>
              <label className="row"><input type="checkbox" checked={compareImages.includes(path)} onChange={() => toggleCompare(path)} /> Compare</label>
            </div>
          ))}
        </div>
        <div className="preview">
          {selectedImage ? <ResolvedImage path={selectedImage} alt="preview" /> : <div>No preview</div>}
        </div>
        {compareImages.length > 0 && (
          <div className="compare-grid">
            {compareImages.map((path) => (
              <ResolvedImage key={path} path={path} alt="compare" />
            ))}
          </div>
        )}
      </section>
    </div>
  );
}

export default App;
