import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
import { NavLink, Navigate, Outlet, useLocation } from "react-router-dom";
import clsx from "clsx";
import { useQueryClient } from "react-query";

import { Routes } from "~/app/router/constants";
import {
  useAdminLogin,
  useAdminLogout,
  useAdminOverview,
} from "~/shared/services/admin";
import { clearAdminAuth, getAdminAuthSnapshot } from "~/shared/libs/admin-auth";
import { isUnauthorizedError } from "~/shared/services/admin";
import { ADMIN_SECTIONS, DEFAULT_ADMIN_SECTION, type AdminSection } from "./config";
import { AdminContext } from "./context";
import type { AuthState, FlashMessage } from "./types";

const initialAuthState: AuthState = getAdminAuthSnapshot().token ? "checking" : "unauthorized";

const resolveErrorMessage = (error: unknown) => {
  if (error && typeof error === "object" && "message" in error && typeof (error as any).message === "string") {
    return (error as any).message as string;
  }
  return "Неизвестная ошибка";
};

const AdminFlash = ({ flash, onClose }: { flash: FlashMessage | null; onClose: () => void }) => {
  if (!flash) {
    return null;
  }
  const tone =
    flash.type === "success"
      ? "border-emerald-500/60 bg-emerald-500/15 text-emerald-50"
      : flash.type === "error"
      ? "border-rose-500/60 bg-rose-500/15 text-rose-50"
      : "border-sky-500/60 bg-sky-500/15 text-sky-50";
  return (
    <div className="pointer-events-none fixed inset-x-4 top-4 z-50 flex justify-center sm:inset-x-auto sm:left-auto sm:right-6">
      <div
        className={clsx(
          "pointer-events-auto flex w-full max-w-md items-start gap-4 rounded-2xl border px-5 py-4 text-sm shadow-2xl shadow-black/40 backdrop-blur-md",
          tone,
        )}
      >
        <span className="flex-1 break-words">{flash.message}</span>
        <button
          type="button"
          className="text-xs font-semibold uppercase tracking-wide text-slate-200 transition hover:text-white"
          onClick={onClose}
        >
          Закрыть
        </button>
      </div>
    </div>
  );
};

const AdminLoginForm = ({
  token,
  onTokenChange,
  onSubmit,
  isSubmitting,
}: {
  token: string;
  onTokenChange: (value: string) => void;
  onSubmit: () => void;
  isSubmitting: boolean;
}) => {
  return (
    <div className="mx-auto max-w-xl rounded-2xl border border-slate-800 bg-slate-900/60 p-8 shadow-xl shadow-black/50">
      <h1 className="text-3xl font-semibold text-slate-100">Админ-панель узла</h1>
      <p className="mt-2 text-sm text-slate-400">
        Введите секретный токен ADMIN_API_TOKEN, чтобы получить доступ к мониторингу и управлению.
      </p>
      <form
        className="mt-6 space-y-4"
        onSubmit={(event) => {
          event.preventDefault();
          onSubmit();
        }}
      >
        <label className="block text-sm font-medium text-slate-200">
          Админ-токен
          <input
            type="password"
            className="mt-1 w-full rounded-lg border border-slate-700 bg-slate-950 px-3 py-2 text-base text-slate-100 shadow-inner focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/40"
            value={token}
            onChange={(event) => onTokenChange(event.target.value)}
            placeholder="••••••"
            autoComplete="off"
          />
        </label>
        <div className="flex items-center justify-between">
          <button
            type="submit"
            className="inline-flex items-center justify-center rounded-lg bg-sky-600 px-4 py-2 text-sm font-semibold text-white transition hover:bg-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500/60 disabled:cursor-not-allowed disabled:bg-slate-700"
            disabled={isSubmitting}
          >
            {isSubmitting ? "Проверяем…" : "Войти"}
          </button>
          <span className="text-xs text-slate-500">
            Cookie max-age {Math.round(172800 / 3600)} ч
          </span>
        </div>
      </form>
    </div>
  );
};

const MobileNav = ({ sections, currentPath }: { sections: AdminSection[]; currentPath: string }) => (
  <select
    className="w-full rounded-lg border border-slate-700 bg-slate-900 px-3 py-2 text-sm text-slate-200 focus:border-sky-500 focus:outline-none focus:ring-1 focus:ring-sky-500 md:hidden"
    value={currentPath}
    onChange={(event) => {
      const next = event.target.value;
      if (next !== currentPath) {
        window.location.assign(next);
      }
    }}
  >
    {sections.map((section) => {
      const to = `${Routes.Admin}/${section.path}`;
      return (
        <option key={section.id} value={to}>
          {section.label}
        </option>
      );
    })}
  </select>
);

const DesktopNav = ({
  sections,
  currentPath,
}: {
  sections: AdminSection[];
  currentPath: string;
}) => {
  return (
    <nav className="hidden w-60 shrink-0 flex-col gap-1 md:flex">
      {sections.map((section) => {
        const to = `${Routes.Admin}/${section.path}`;
        const isActive = currentPath.startsWith(to);
        return (
          <NavLink
            key={section.id}
            to={to}
            className={clsx(
              "rounded-xl px-4 py-3 text-sm font-medium transition",
              isActive
                ? "bg-sky-500/10 text-sky-200 ring-1 ring-sky-500/40"
                : "text-slate-300 hover:bg-slate-900/60 hover:text-white",
            )}
            end
          >
            <div className="flex flex-col">
              <span>{section.label}</span>
              <span className="mt-1 text-xs text-slate-500">{section.description}</span>
            </div>
          </NavLink>
        );
      })}
    </nav>
  );
};

const AdminLayoutFrame = ({ children }: { children: ReactNode }) => {
  const location = useLocation();
  const currentPath = location.pathname;

  return (
    <div className="min-h-screen bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 text-slate-100">
      <header className="border-b border-slate-800 bg-slate-950/70 backdrop-blur">
        <div className="flex w-full items-center justify-between gap-4 px-4 py-4 sm:px-6 lg:px-8">
          <div>
            <h1 className="text-xl font-semibold text-white">MY Admin</h1>
            <p className="text-xs text-slate-500">Мониторинг и управление узлом</p>
          </div>
          <div className="flex items-center gap-3 md:hidden">
            <MobileNav sections={ADMIN_SECTIONS} currentPath={currentPath} />
          </div>
        </div>
      </header>
      <main className="flex w-full flex-1 flex-col gap-6 px-4 py-6 sm:px-6 lg:px-8 md:flex-row">
        <DesktopNav sections={ADMIN_SECTIONS} currentPath={currentPath} />
        <div className="w-full max-w-full md:flex-1">
          <MobileNav sections={ADMIN_SECTIONS} currentPath={currentPath} />
          <div className="mt-4 space-y-6 md:mt-0">
            {children}
          </div>
        </div>
      </main>
    </div>
  );
};

export const AdminShell = () => {
  const queryClient = useQueryClient();
  const [authState, setAuthState] = useState<AuthState>(initialAuthState);
  const [token, setToken] = useState("");
  const [flash, setFlash] = useState<FlashMessage | null>(null);

  useEffect(() => {
    if (!flash) {
      return;
    }
    const timeout = setTimeout(() => setFlash(null), 6000);
    return () => clearTimeout(timeout);
  }, [flash]);

  useEffect(() => {
    if (authState === "unauthorized") {
      queryClient.removeQueries({
        predicate: (query) => Array.isArray(query.queryKey) && query.queryKey[0] === "admin",
      });
    }
  }, [authState, queryClient]);

  const pushFlash = useCallback((message: FlashMessage) => {
    setFlash(message);
  }, []);

  const clearFlash = useCallback(() => {
    setFlash(null);
  }, []);

  const handleRequestError = useCallback(
    (error: unknown, fallbackMessage: string) => {
      if (isUnauthorizedError(error)) {
        clearAdminAuth();
        setAuthState("unauthorized");
        pushFlash({ type: "info", message: "Сессия истекла. Введите админ-токен заново." });
        return;
      }
      const tail = resolveErrorMessage(error);
      pushFlash({
        type: "error",
        message: `${fallbackMessage}: ${tail}`,
      });
    },
    [pushFlash],
  );

  const invalidateAll = useCallback(async () => {
    await queryClient.invalidateQueries({
      predicate: (query) => Array.isArray(query.queryKey) && query.queryKey[0] === "admin",
    });
  }, [queryClient]);

  useAdminOverview({
    enabled: authState === "checking",
    retry: false,
    onSuccess: () => {
      setAuthState("authorized");
    },
    onError: (error) => {
      handleRequestError(error, "Не удалось проверить админ-сессию");
    },
  });

  const loginMutation = useAdminLogin({
    onSuccess: async () => {
      setAuthState("authorized");
      setToken("");
      pushFlash({ type: "success", message: "Админ-сессия активирована" });
      await invalidateAll();
    },
    onError: (error) => {
      if (isUnauthorizedError(error)) {
        clearAdminAuth();
        pushFlash({ type: "error", message: "Неверный токен" });
        return;
      }
      handleRequestError(error, "Ошибка входа");
    },
  });

  const logoutMutation = useAdminLogout({
    onSuccess: async () => {
      setAuthState("unauthorized");
      pushFlash({ type: "info", message: "Сессия завершена" });
      await invalidateAll();
    },
    onError: (error) => {
      handleRequestError(error, "Ошибка выхода");
    },
  });

  const contextValue = useMemo(
    () => ({
      authState,
      isAuthorized: authState === "authorized",
      pushFlash,
      clearFlash,
      handleRequestError,
      invalidateAll,
    }),
    [authState, pushFlash, clearFlash, handleRequestError, invalidateAll],
  );

  return (
    <AdminContext.Provider value={contextValue}>
      {authState !== "authorized" ? (
        <div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-slate-950 via-slate-900 to-slate-950 px-6 py-10">
          <div className="w-full max-w-xl space-y-6">
            <AdminLoginForm
              token={token}
              onTokenChange={setToken}
              onSubmit={() => {
                if (!token) {
                  pushFlash({ type: "info", message: "Введите токен" });
                  return;
                }
                loginMutation.mutate({ secret: token });
              }}
              isSubmitting={loginMutation.isLoading}
            />
          </div>
        </div>
      ) : (
        <AdminLayoutFrame>
          <div className="flex items-center justify-between gap-3">
            <div className="flex items-center gap-3">
              <span className="rounded-full bg-emerald-500/10 px-3 py-1 text-xs font-semibold text-emerald-200 ring-1 ring-emerald-500/40">
                Авторизован
              </span>
              <button
                type="button"
                className="rounded-lg border border-slate-700 px-3 py-1 text-xs font-semibold text-slate-300 transition hover:border-sky-500 hover:text-white"
                onClick={() => invalidateAll()}
              >
                Обновить все данные
              </button>
            </div>
            <button
              type="button"
              className="rounded-lg bg-rose-600 px-3 py-1 text-xs font-semibold text-white transition hover:bg-rose-500 disabled:cursor-not-allowed disabled:bg-rose-900/50"
              onClick={() => logoutMutation.mutate()}
              disabled={logoutMutation.isLoading}
            >
              Выйти
            </button>
          </div>
          <Outlet />
        </AdminLayoutFrame>
      )}
      <AdminFlash flash={flash} onClose={clearFlash} />
    </AdminContext.Provider>
  );
};

export const AdminPage = AdminShell;

export const AdminIndexRedirect = () => {
  return <Navigate to={`${Routes.Admin}/${DEFAULT_ADMIN_SECTION.path}`} replace />;
};
