"use client";

import { useCallback, useEffect, useState } from "react";
import { useTranslations } from "next-intl";

import { Button } from "@hexahost/ui";

import {
  completeWorldUpload,
  getWorldInfo,
  initiateWorldUpload,
  requestWorldDownload,
  type WorldSummary,
} from "@/lib/api/worlds";
import { getBackupDownloadUrl } from "@/lib/api/backups";

interface ServerWorldsProps {
  serverId: string;
}

function formatBytes(value: string): string {
  const bytes = Number(value);
  if (Number.isNaN(bytes)) {
    return value;
  }
  if (bytes < 1024 * 1024) {
    return `${(bytes / 1024).toFixed(1)} KB`;
  }
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

export function ServerWorlds({ serverId }: ServerWorldsProps) {
  const t = useTranslations("servers.worlds");
  const [activeWorldName, setActiveWorldName] = useState("world");
  const [worlds, setWorlds] = useState<WorldSummary[]>([]);
  const [loading, setLoading] = useState(true);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [worldName, setWorldName] = useState("world");

  const refresh = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const info = await getWorldInfo(serverId);
      setActiveWorldName(info.activeWorldName);
      setWorlds(info.worlds);
    } catch (err) {
      setError(err instanceof Error ? err.message : t("loadError"));
    } finally {
      setLoading(false);
    }
  }, [serverId, t]);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  async function handleUpload(file: File) {
    setBusy(true);
    setError(null);
    try {
      const init = await initiateWorldUpload(serverId, worldName);
      const response = await fetch(init.uploadUrl, {
        method: "PUT",
        body: file,
        headers: { "Content-Type": "application/gzip" },
      });
      if (!response.ok) {
        throw new Error(t("uploadError"));
      }
      await completeWorldUpload(serverId, init.uploadId);
      await refresh();
    } catch (err) {
      setError(err instanceof Error ? err.message : t("uploadError"));
    } finally {
      setBusy(false);
    }
  }

  async function handleDownload() {
    setBusy(true);
    setError(null);
    try {
      const { backupId } = await requestWorldDownload(serverId);
      const { downloadUrl } = await getBackupDownloadUrl(serverId, backupId);
      if (downloadUrl) {
        window.open(downloadUrl, "_blank", "noopener,noreferrer");
      } else {
        setError(t("downloadPending"));
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : t("downloadError"));
    } finally {
      setBusy(false);
    }
  }

  if (loading) {
    return <p className="text-sm text-zinc-500">{t("loading")}</p>;
  }

  return (
    <div className="space-y-6">
      {error ? (
        <p className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900 dark:bg-red-950 dark:text-red-300">
          {error}
        </p>
      ) : null}

      <div className="rounded-lg border border-zinc-200 p-4 dark:border-zinc-800">
        <p className="text-sm text-zinc-600 dark:text-zinc-400">
          {t("activeWorld", { name: activeWorldName })}
        </p>
        <p className="mt-1 text-xs text-zinc-500">{t("stoppedHint")}</p>
      </div>

      <div className="flex flex-wrap gap-3 items-end">
        <label className="block text-sm">
          <span className="mb-1 block text-zinc-600 dark:text-zinc-400">
            {t("worldName")}
          </span>
          <input
            className="rounded-md border border-zinc-300 bg-white px-3 py-2 text-sm dark:border-zinc-700 dark:bg-zinc-950"
            value={worldName}
            onChange={(event) => setWorldName(event.target.value)}
          />
        </label>
        <label className="block text-sm">
          <span className="mb-1 block text-zinc-600 dark:text-zinc-400">
            {t("uploadArchive")}
          </span>
          <input
            type="file"
            accept=".tar.gz,.tgz,application/gzip"
            disabled={busy}
            onChange={(event) => {
              const file = event.target.files?.[0];
              if (file) {
                void handleUpload(file);
              }
            }}
          />
        </label>
        <Button variant="secondary" onClick={() => void handleDownload()} disabled={busy}>
          {t("download")}
        </Button>
      </div>

      <ul className="divide-y divide-zinc-200 rounded-lg border border-zinc-200 dark:divide-zinc-800 dark:border-zinc-800">
        {worlds.length === 0 ? (
          <li className="px-4 py-6 text-center text-sm text-zinc-500">{t("empty")}</li>
        ) : (
          worlds.map((world) => (
            <li key={world.name} className="flex items-center justify-between px-4 py-3 text-sm">
              <div>
                <p className="font-medium">{world.name}</p>
                <p className="text-zinc-500">
                  {world.hasLevelDat ? t("validWorld") : t("invalidWorld")} ·{" "}
                  {formatBytes(world.sizeBytes)}
                </p>
              </div>
              {world.name === activeWorldName ? (
                <span className="text-xs text-sky-600 dark:text-sky-400">{t("active")}</span>
              ) : null}
            </li>
          ))
        )}
      </ul>
    </div>
  );
}
