import { useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router";

import { API_URL } from "../config/api.ts";
import type { Dump, UpdateDumpRequest } from "../model.ts";
import { deserializeDump } from "../model.ts";
import { useRequiredAuth } from "../hooks/useAuth.ts";
import { formatBytes } from "../utils/format.ts";
import { PageShell } from "../components/PageShell.tsx";
import { PageError } from "../components/PageError.tsx";
import { ConfirmModal } from "../components/ConfirmModal.tsx";
import RichContentCard from "../components/RichContentCard.tsx";
import FilePreview from "../components/FilePreview.tsx";

type DumpEditState =
  | { status: "loading" }
  | { status: "error"; error: string }
  | { status: "loaded"; dump: Dump };

export function DumpEdit() {
  const { selectedDump } = useParams();
  const navigate = useNavigate();
  const { authFetch } = useRequiredAuth();

  const [state, setState] = useState<DumpEditState>({ status: "loading" });
  const [url, setUrl] = useState("");
  const [comment, setComment] = useState("");
  const [newFile, setNewFile] = useState<File | null>(null);
  const [confirmDelete, setConfirmDelete] = useState(false);

  useEffect(() => {
    if (!selectedDump) return;

    setState({ status: "loading" });

    (async () => {
      try {
        const res = await fetch(`${API_URL}/api/dumps/${selectedDump}`, {
          cache: "no-store",
        });
        if (!res.ok) throw new Error(`HTTP ${res.status}`);

        const apiResponse = await res.json();

        if (apiResponse.success) {
          const dump: Dump = deserializeDump(apiResponse.data);
          setUrl(dump.url ?? "");
          setComment(dump.comment ?? "");
          setState({ status: "loaded", dump });
        } else {
          setState({ status: "error", error: apiResponse.error.message });
        }
      } catch (err) {
        setState({
          status: "error",
          error: err instanceof Error ? err.message : "Load failed",
        });
      }
    })();
  }, [selectedDump]);

  const handleSave = async () => {
    if (state.status !== "loaded") return;

    let res: Response;

    if (state.dump.kind === "file" && newFile) {
      const formData = new FormData();
      formData.append("file", newFile);
      if (comment.trim()) formData.append("comment", comment.trim());
      res = await authFetch(`${API_URL}/api/dumps/${state.dump.id}/file`, {
        method: "PUT",
        body: formData,
      });
    } else {
      const body: UpdateDumpRequest = state.dump.kind === "url"
        ? { url: url.trim() || undefined, comment: comment.trim() || undefined }
        : { comment: comment.trim() || undefined };
      res = await authFetch(`${API_URL}/api/dumps/${state.dump.id}`, {
        method: "PUT",
        body: JSON.stringify(body),
      });
    }

    if (!res.ok) {
      setState({ status: "error", error: `Update failed (${res.status})` });
      return;
    }

    const apiResponse = await res.json();
    if (!apiResponse.success) {
      setState({
        status: "error",
        error: apiResponse.error?.message ?? "Update failed",
      });
      return;
    }

    const updatedDump: Dump = deserializeDump(apiResponse.data);
    setState({ status: "loaded", dump: updatedDump });
    setNewFile(null);
    navigate(`/dumps/${updatedDump.id}`, { state: { dump: updatedDump } });
  };

  const handleDelete = async () => {
    if (state.status !== "loaded") return;

    const res = await authFetch(`${API_URL}/api/dumps/${state.dump.id}`, {
      method: "DELETE",
    });

    if (!res.ok) {
      setState({ status: "error", error: `Delete failed (${res.status})` });
      return;
    }

    navigate("/", { state: { deletedDumpId: state.dump.id } });
  };

  if (state.status === "loading") {
    return (
      <PageShell>
        <p className="page-loading">Loading dump…</p>
      </PageShell>
    );
  }

  if (state.status === "error") {
    return (
      <PageError
        message={state.error}
        actions={
          <>
            <button
              className="logout-btn"
              type="button"
              onClick={() => globalThis.location.reload()}
            >
              Retry
            </button>
            <button
              className="logout-btn"
              type="button"
              onClick={() => navigate("/")}
            >
              ← Back to all dumps
            </button>
          </>
        }
      />
    );
  }

  const { dump } = state;

  return (
    <PageShell>
      <div className="form-page form-page--two-col">
        <div className="form-page-header">
          <p className="form-page-eyebrow">Editing</p>
          <h1 className="form-page-title">{dump.title}</h1>
        </div>

        <div className="dump-edit-preview">
          {dump.kind === "file"
            ? <FilePreview dump={dump} />
            : dump.richContent
            ? <RichContentCard richContent={dump.richContent} />
            : dump.url && (
              <a
                href={dump.url}
                target="_blank"
                rel="noopener noreferrer"
                className="dump-url-link"
              >
                {dump.url}
              </a>
            )}
        </div>

        <form
          className="dump-form"
          onSubmit={(e) => {
            e.preventDefault();
            handleSave();
          }}
        >
          {dump.kind === "url"
            ? (
              <div className="form-group">
                <label htmlFor="url">URL</label>
                <input
                  id="url"
                  type="url"
                  value={url}
                  onChange={(e) => setUrl(e.currentTarget.value)}
                  placeholder="https://..."
                  required
                />
              </div>
            )
            : (
              <div className="form-group">
                <p className="dump-file-notice">
                  <strong>{dump.fileName}</strong>
                  {dump.fileSize != null && ` — ${formatBytes(dump.fileSize)}`}
                </p>
                <label htmlFor="replace-file">Replace file</label>
                <input
                  id="replace-file"
                  type="file"
                  onChange={(e) => setNewFile(e.target.files?.[0] ?? null)}
                />
                {newFile && (
                  <p className="file-input-info">
                    {newFile.name} — {formatBytes(newFile.size)}
                  </p>
                )}
              </div>
            )}

          <div className="form-group">
            <label htmlFor="comment">Why are you dumping this?</label>
            <textarea
              id="comment"
              value={comment}
              onChange={(e) => setComment(e.currentTarget.value)}
              placeholder="Tell the community what makes this worth their time..."
              rows={3}
            />
          </div>

          <div className="form-actions">
            <button
              type="button"
              onClick={() => setConfirmDelete(true)}
              className="btn-danger"
            >
              Delete dump
            </button>
            <div className="form-actions-right">
              <Link to={`/dumps/${dump.id}`} className="form-cancel">
                Cancel
              </Link>
              <button type="submit" className="btn-primary">Save</button>
            </div>
          </div>
        </form>
      </div>
      {confirmDelete && (
        <ConfirmModal
          message="Delete this dump? This cannot be undone."
          confirmLabel="Delete dump"
          onConfirm={handleDelete}
          onCancel={() => setConfirmDelete(false)}
        />
      )}
    </PageShell>
  );
}
