import { useEffect, useState } from "react";
import { Link, useNavigate, useParams } from "react-router";
import { t } from "@lingui/core/macro";
import { Trans } from "@lingui/react/macro";

import { API_URL, VALIDATION } from "../config/api.ts";
import type { Dump, RawDump, UpdateDumpRequest } from "../model.ts";
import { deserializeDump, parseAPIResponse } from "../model.ts";
import { useRequiredAuth } from "../hooks/useAuth.ts";
import { formatBytes } from "../utils/format.ts";
import { dumpUrl } from "../utils/urls.ts";
import { PageShell } from "../components/PageShell.tsx";
import { PageError } from "../components/PageError.tsx";
import { friendlyFetchError } from "../utils/apiError.ts";
import { ConfirmModal } from "../components/ConfirmModal.tsx";
import RichContentCard from "../components/RichContentCard.tsx";
import FilePreview from "../components/FilePreview.tsx";
import { TextEditor } from "../components/TextEditor.tsx";
import { FileDropZone } from "../components/FileDropZone.tsx";

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

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

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

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

    setState({ status: "loading" });

    (async () => {
      try {
        const res = await fetch(`${API_URL}/api/dumps/${selectedDump}`, {
          cache: "no-store",
          headers: token ? { Authorization: `Bearer ${token}` } : {},
        });
        const apiResponse = parseAPIResponse<RawDump>(await res.json());

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

  const handleSave = async () => {
    if (
      state.status !== "loaded" || comment.length > VALIDATION.DUMP_COMMENT_MAX
    ) 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,
          isPrivate,
        }
        : { comment: comment.trim() || undefined, isPrivate };
      res = await authFetch(`${API_URL}/api/dumps/${state.dump.id}`, {
        method: "PUT",
        body: JSON.stringify(body),
      });
    }

    const apiResponse = parseAPIResponse<RawDump>(await res.json());
    if (!apiResponse.success) {
      setState({ status: "error", error: apiResponse.error.message });
      return;
    }

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

  const handleRefreshMetadata = async () => {
    if (state.status !== "loaded" || state.dump.kind !== "url") return;

    setRefreshing(true);
    try {
      const res = await authFetch(
        `${API_URL}/api/dumps/${state.dump.id}/refresh-metadata`,
        { method: "POST" },
      );
      const apiResponse = await res.json();
      if (apiResponse.success) {
        const updatedDump: Dump = deserializeDump(apiResponse.data);
        setState({ status: "loaded", dump: updatedDump });
      }
    } finally {
      setRefreshing(false);
    }
  };

  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">
          <Trans>Loading dump…</Trans>
        </p>
      </PageShell>
    );
  }

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

  const { dump } = state;

  return (
    <PageShell>
      <div className="form-page form-page--two-col">
        <div className="form-page-header">
          <p className="form-page-eyebrow">
            <Trans>Editing</Trans>
          </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>
            )}
          {dump.kind === "url" && (
            <button
              type="button"
              className="btn-secondary dump-edit-refresh"
              onClick={handleRefreshMetadata}
              disabled={refreshing}
            >
              {refreshing
                ? <Trans>Refreshing…</Trans>
                : <Trans>Refresh metadata</Trans>}
            </button>
          )}
        </div>

        <form
          className="dump-form"
          onSubmit={(e) => {
            e.preventDefault();
            handleSave();
          }}
        >
          {dump.kind === "url"
            ? (
              <div className="form-group">
                <label htmlFor="url">
                  <Trans>URL</Trans>
                </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>
                <FileDropZone
                  file={newFile}
                  onChange={setNewFile}
                  label={t`Replace file`}
                  hint={t`Drop a replacement here`}
                  showLimit={false}
                />
              </div>
            )}

          <div className="form-group">
            <label htmlFor="comment">
              <Trans>Why?</Trans>
            </label>
            <TextEditor
              id="comment"
              value={comment}
              onChange={setComment}
              placeholder={t`What makes it worth it?`}
              rows={3}
              maxLength={VALIDATION.DUMP_COMMENT_MAX}
            />
          </div>

          <div className="visibility-toggle">
            <button
              type="button"
              className={!isPrivate ? "active" : ""}
              onClick={() => setIsPrivate(false)}
            >
              <Trans>Public</Trans>
            </button>
            <button
              type="button"
              className={isPrivate ? "active" : ""}
              onClick={() => setIsPrivate(true)}
            >
              <Trans>Private</Trans>
            </button>
          </div>

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