"use client";

import { Button } from "@hexahost/ui";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useTranslations } from "next-intl";
import { useEffect, useState } from "react";
import { ApiError } from "@/lib/api/auth";
import { listFiles, readFile, writeFile } from "@/lib/api/files";
import { getServer } from "@/lib/api/servers";

interface ServerFilesProps {
  serverId: string;
}

const textareaClassName =
  "min-h-80 w-full rounded-md border border-zinc-300 bg-white px-3 py-2 font-mono text-sm text-zinc-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sky-500 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-100";

export function ServerFiles({ serverId }: ServerFilesProps) {
  const t = useTranslations("servers.files");
  const queryClient = useQueryClient();
  const [currentPath, setCurrentPath] = useState("");
  const [selectedFile, setSelectedFile] = useState<string | null>(null);
  const [editorContent, setEditorContent] = useState("");
  const [fileVersion, setFileVersion] = useState<number | undefined>();
  const [error, setError] = useState<string | null>(null);
  const [saveSuccess, setSaveSuccess] = useState(false);

  const { data: server } = useQuery({
    queryKey: ["server", serverId],
    queryFn: () => getServer(serverId),
  });

  const canAccessFiles =
    server?.status === "RUNNING" || server?.status === "STOPPED";

  const {
    data: listing,
    isLoading: listingLoading,
    isError: listingError,
  } = useQuery({
    queryKey: ["server-files", serverId, currentPath],
    queryFn: () => listFiles(serverId, currentPath),
    enabled: Boolean(server && canAccessFiles),
  });

  const {
    data: fileData,
    isLoading: fileLoading,
    isError: fileError,
  } = useQuery({
    queryKey: ["server-file", serverId, selectedFile],
    queryFn: () => readFile(serverId, selectedFile!),
    enabled: Boolean(selectedFile && canAccessFiles),
  });

  useEffect(() => {
    if (fileData) {
      setEditorContent(fileData.content);
      setFileVersion(fileData.version);
    }
  }, [fileData]);

  const saveMutation = useMutation({
    mutationFn: () =>
      writeFile(serverId, {
        path: selectedFile!,
        content: editorContent,
        version: fileVersion,
      }),
    onSuccess: (result) => {
      setError(null);
      setSaveSuccess(true);
      setFileVersion(result.version);
      void queryClient.invalidateQueries({ queryKey: ["server-file", serverId, selectedFile] });
      setTimeout(() => setSaveSuccess(false), 2000);
    },
    onError: (err: unknown) => {
      setSaveSuccess(false);
      setError(err instanceof ApiError ? (err.detail ?? err.title) : t("errors.saveFailed"));
    },
  });

  function handleSelectEntry(path: string, isDir: boolean) {
    setError(null);
    setSaveSuccess(false);
    if (isDir) {
      setCurrentPath(path);
      setSelectedFile(null);
      setEditorContent("");
      return;
    }
    setSelectedFile(path);
    setEditorContent("");
    setFileVersion(undefined);
  }

  function handleNavigateUp() {
    if (!currentPath) {
      return;
    }
    const segments = currentPath.split("/").filter(Boolean);
    segments.pop();
    setCurrentPath(segments.join("/"));
    setSelectedFile(null);
    setEditorContent("");
    setError(null);
  }

  if (!server) {
    return <p className="text-sm text-zinc-600 dark:text-zinc-400">{t("loading")}</p>;
  }

  if (!canAccessFiles) {
    return (
      <div className="rounded-lg border border-amber-200 bg-amber-50 p-4 dark:border-amber-900 dark:bg-amber-950/40">
        <p className="text-sm text-amber-800 dark:text-amber-200">{t("notAvailable")}</p>
      </div>
    );
  }

  const isReadOnly = server.status === "STOPPED";

  return (
    <div className="grid gap-6 lg:grid-cols-2">
      <div className="space-y-3">
        <div className="flex items-center justify-between gap-2">
          <h2 className="text-sm font-medium text-zinc-900 dark:text-zinc-100">{t("browser")}</h2>
          {currentPath ? (
            <Button size="sm" variant="secondary" onClick={handleNavigateUp}>
              {t("up")}
            </Button>
          ) : null}
        </div>

        <p className="truncate font-mono text-xs text-zinc-500 dark:text-zinc-400">
          /{currentPath || ""}
        </p>

        {isReadOnly ? (
          <p className="text-xs text-amber-700 dark:text-amber-300">{t("readOnlyStopped")}</p>
        ) : null}

        {listingLoading ? (
          <p className="text-sm text-zinc-600 dark:text-zinc-400">{t("loading")}</p>
        ) : listingError ? (
          <p className="text-sm text-red-600 dark:text-red-400">{t("errors.loadFailed")}</p>
        ) : (
          <ul className="divide-y divide-zinc-200 rounded-lg border border-zinc-200 dark:divide-zinc-800 dark:border-zinc-800">
            {(listing?.entries ?? []).length === 0 ? (
              <li className="px-3 py-2 text-sm text-zinc-500 dark:text-zinc-400">{t("empty")}</li>
            ) : (
              (listing?.entries ?? []).map((entry) => (
                <li key={entry.path}>
                  <button
                    type="button"
                    onClick={() => handleSelectEntry(entry.path, entry.isDir)}
                    className="flex w-full items-center gap-2 px-3 py-2 text-left text-sm hover:bg-zinc-50 dark:hover:bg-zinc-900"
                  >
                    <span className="w-8 shrink-0 text-xs text-zinc-400">
                      {entry.isDir ? "DIR" : "FILE"}
                    </span>
                    <span className="truncate text-zinc-900 dark:text-zinc-100">{entry.name}</span>
                    {!entry.isDir ? (
                      <span className="ml-auto text-xs text-zinc-500">{entry.size} B</span>
                    ) : null}
                  </button>
                </li>
              ))
            )}
          </ul>
        )}
      </div>

      <div className="space-y-3">
        <h2 className="text-sm font-medium text-zinc-900 dark:text-zinc-100">{t("editor")}</h2>

        {!selectedFile ? (
          <p className="text-sm text-zinc-600 dark:text-zinc-400">{t("selectFile")}</p>
        ) : fileLoading ? (
          <p className="text-sm text-zinc-600 dark:text-zinc-400">{t("loading")}</p>
        ) : fileError ? (
          <p className="text-sm text-red-600 dark:text-red-400">{t("errors.readFailed")}</p>
        ) : (
          <div className="space-y-3">
            <p className="truncate font-mono text-xs text-zinc-500 dark:text-zinc-400">
              {selectedFile}
            </p>

            {fileData?.truncated ? (
              <p className="text-xs text-amber-700 dark:text-amber-300">{t("truncated")}</p>
            ) : null}

            <textarea
              className={textareaClassName}
              value={editorContent}
              onChange={(event) => {
                setEditorContent(event.target.value);
                setSaveSuccess(false);
              }}
              readOnly={isReadOnly}
              spellCheck={false}
            />

            {error ? (
              <p className="text-sm text-red-600 dark:text-red-400" role="alert">
                {error}
              </p>
            ) : null}

            {saveSuccess ? (
              <p className="text-sm text-green-600 dark:text-green-400">{t("saved")}</p>
            ) : null}

            {!isReadOnly ? (
              <Button
                onClick={() => saveMutation.mutate()}
                disabled={saveMutation.isPending}
              >
                {saveMutation.isPending ? t("saving") : t("save")}
              </Button>
            ) : null}
          </div>
        )}
      </div>
    </div>
  );
}
