import { useEffect, useState } from "react";

const apiBase = import.meta.env.VITE_API_BASE_URL || "http://localhost:8080";

function formatBytes(size) {
  if (size === 0) return "0 B";
  const units = ["B", "KB", "MB", "GB", "TB"];
  const index = Math.min(Math.floor(Math.log(size) / Math.log(1024)), units.length - 1);
  const value = size / 1024 ** index;
  return `${value.toFixed(value >= 10 || index === 0 ? 0 : 1)} ${units[index]}`;
}

function formatDate(value) {
  return new Intl.DateTimeFormat(undefined, {
    dateStyle: "medium",
    timeStyle: "short",
  }).format(new Date(value));
}

async function readError(response, fallback) {
  const contentType = response.headers.get("content-type") || "";

  if (contentType.includes("application/json")) {
    const payload = await response.json();
    if (payload?.error) {
      return payload.error;
    }
  }

  const text = await response.text();
  return text.trim() || fallback;
}

export default function App() {
  const [files, setFiles] = useState([]);
  const [selectedFile, setSelectedFile] = useState(null);
  const [keyName, setKeyName] = useState("");
  const [status, setStatus] = useState("Loading files...");
  const [error, setError] = useState("");
  const [busy, setBusy] = useState(false);

  async function loadFiles() {
    try {
      setError("");
      setStatus("Refreshing bucket contents...");
      const response = await fetch(`${apiBase}/api/files`);
      if (!response.ok) {
        throw new Error(await readError(response, `Failed to list files (${response.status})`));
      }
      const payload = await response.json();
      setFiles(payload.files || []);
      setStatus(`Loaded ${payload.files?.length || 0} file${payload.files?.length === 1 ? "" : "s"}.`);
    } catch (err) {
      setError(err.message);
      setStatus("Unable to load files.");
    }
  }

  useEffect(() => {
    loadFiles();
  }, []);

  async function handleUpload(event) {
    event.preventDefault();
    if (!selectedFile) {
      setError("Choose a file before uploading.");
      return;
    }

    const body = new FormData();
    body.append("file", selectedFile);
    if (keyName.trim()) {
      body.append("key", keyName.trim());
    }

    try {
      setBusy(true);
      setError("");
      setStatus(`Uploading ${selectedFile.name}...`);
      const response = await fetch(`${apiBase}/api/files`, {
        method: "POST",
        body,
      });
      if (!response.ok) {
        throw new Error(await readError(response, `Upload failed (${response.status})`));
      }
      setSelectedFile(null);
      setKeyName("");
      event.target.reset();
      await loadFiles();
      setStatus(`Uploaded ${selectedFile.name}.`);
    } catch (err) {
      setError(err.message);
      setStatus("Upload failed.");
    } finally {
      setBusy(false);
    }
  }

  async function handleDelete(fileKey) {
    if (!window.confirm(`Delete ${fileKey}?`)) {
      return;
    }

    try {
      setBusy(true);
      setError("");
      setStatus(`Deleting ${fileKey}...`);
      const response = await fetch(`${apiBase}/api/files/${encodeURIComponent(fileKey)}`, {
        method: "DELETE",
      });
      if (!response.ok) {
        throw new Error(await readError(response, `Delete failed (${response.status})`));
      }
      await loadFiles();
      setStatus(`Deleted ${fileKey}.`);
    } catch (err) {
      setError(err.message);
      setStatus("Delete failed.");
    } finally {
      setBusy(false);
    }
  }

  function handleDownload(fileKey) {
    window.location.href = `${apiBase}/api/files/${encodeURIComponent(fileKey)}`;
  }

  return (
    <main className="shell">
      <section className="hero">
        <div>
          <p className="eyebrow">React + Go + S3</p>
          <h1>S3 Mover</h1>
          <p className="lede">
            Browse bucket contents and move files in and out of S3 without leaving the browser.
          </p>
        </div>
        <div className="status-card">
          <span>Status</span>
          <strong>{status}</strong>
          {error ? <p>{error}</p> : null}
        </div>
      </section>

      <section className="panel upload-panel">
        <div>
          <h2>Upload a file</h2>
          <p>Leave the object key blank to reuse the local filename.</p>
        </div>
        <form onSubmit={handleUpload} className="upload-form">
          <label>
            <span>File</span>
            <input
              type="file"
              onChange={(event) => setSelectedFile(event.target.files?.[0] || null)}
              disabled={busy}
            />
          </label>
          <label>
            <span>Object key</span>
            <input
              type="text"
              placeholder="reports/quarterly.csv"
              value={keyName}
              onChange={(event) => setKeyName(event.target.value)}
              disabled={busy}
            />
          </label>
          <button type="submit" disabled={busy || !selectedFile}>
            {busy ? "Working..." : "Upload"}
          </button>
        </form>
      </section>

      <section className="panel">
        <div className="table-header">
          <div>
            <h2>Bucket contents</h2>
            <p>{files.length} items visible</p>
          </div>
          <button type="button" className="ghost-button" onClick={loadFiles} disabled={busy}>
            Refresh
          </button>
        </div>

        <div className="file-list">
          {files.length === 0 ? (
            <div className="empty-state">No files found in the configured bucket or prefix.</div>
          ) : (
            files.map((file) => (
              <article className="file-row" key={file.key}>
                <div className="file-meta">
                  <strong>{file.key}</strong>
                  <span>{formatBytes(file.size)}</span>
                  <span>{formatDate(file.lastModified)}</span>
                </div>
                <div className="actions">
                  <button type="button" onClick={() => handleDownload(file.key)} disabled={busy}>
                    Download
                  </button>
                  <button type="button" className="danger" onClick={() => handleDelete(file.key)} disabled={busy}>
                    Delete
                  </button>
                </div>
              </article>
            ))
          )}
        </div>
      </section>
    </main>
  );
}
