// auth.jsx — login-форма + хелперы для API-вызовов.
//
// Сессия — signed cookie 'zxckotik_admin' (ставит бэк). Фронт не хранит
// пароль; для определения статуса делает /api/auth/me.

const { useState: useStateAuth, useEffect: useEffectAuth } = React;

/** GET /api/auth/me — true если есть валидная сессия. */
async function checkAuth() {
  try {
    const res = await fetch("/api/auth/me");
    if (!res.ok) return false;
    const data = await res.json();
    return Boolean(data.authenticated);
  } catch {
    return false;
  }
}

/** POST /api/auth/login — отправить пароль, на успех cookie ставится автоматом. */
async function loginWithPassword(password) {
  try {
    const res = await fetch("/api/auth/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ password }),
    });
    return res.ok;
  } catch {
    return false;
  }
}

async function logoutSession() {
  try { await fetch("/api/auth/logout", { method: "POST" }); } catch {}
}

/** Универсальный wrapper для mutating запросов. На 401 → window-event для login. */
async function apiMutate(method, url, body) {
  const opts = {
    method,
    headers: body ? { "Content-Type": "application/json" } : {},
    body: body ? JSON.stringify(body) : undefined,
  };
  const res = await fetch(url, opts);
  if (res.status === 401) {
    window.dispatchEvent(new CustomEvent("auth-required"));
    throw new Error("auth_required");
  }
  if (!res.ok) {
    const detail = await res.text().catch(() => "");
    throw new Error(`${method} ${url} → ${res.status} ${detail.slice(0, 200)}`);
  }
  const ct = res.headers.get("content-type") || "";
  return ct.includes("application/json") ? res.json() : null;
}


function LoginScreen({ onSuccess }) {
  const [password, setPassword] = useStateAuth("");
  const [loading, setLoading] = useStateAuth(false);
  const [error, setError] = useStateAuth("");

  const submit = async (e) => {
    e.preventDefault();
    if (!password) return;
    setLoading(true);
    setError("");
    const ok = await loginWithPassword(password);
    setLoading(false);
    if (ok) {
      setPassword("");
      onSuccess();
    } else {
      setError("Неверный пароль");
    }
  };

  return (
    <div className="min-h-screen bg-zinc-950 text-zinc-100 flex items-center justify-center p-6">
      <form
        onSubmit={submit}
        className="w-full max-w-sm bg-zinc-900/60 border border-zinc-800/80 rounded-2xl p-8 shadow-2xl"
      >
        <div className="flex items-center gap-3 mb-6">
          <div
            className="w-10 h-10 rounded-xl shadow-lg shrink-0"
            style={{ background: "linear-gradient(135deg, #6366f1, #7c3aed)", boxShadow: "0 10px 20px -10px #6366f180" }}
          />
          <div>
            <div className="text-lg font-semibold tracking-tight">Zxckotik</div>
            <div className="text-xs text-zinc-500">Admin Panel</div>
          </div>
        </div>

        <label className="block">
          <div className="text-xs text-zinc-500 font-medium uppercase tracking-wider mb-2">Пароль</div>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            autoFocus
            placeholder="••••••••"
            className="w-full bg-zinc-800/60 border border-zinc-700/60 rounded-lg px-3 py-2.5 text-sm placeholder:text-zinc-500 focus:outline-none focus:border-indigo-500/50"
          />
        </label>

        {error && (
          <div className="mt-3 text-[12px] text-rose-400 bg-rose-500/10 border border-rose-500/20 rounded-lg px-3 py-2">
            {error}
          </div>
        )}

        <button
          type="submit"
          disabled={loading || !password}
          className="w-full mt-5 px-4 py-2.5 rounded-lg bg-indigo-500 hover:bg-indigo-600 disabled:bg-zinc-800 disabled:text-zinc-500 text-white text-sm font-medium transition-colors"
        >
          {loading ? "Проверяю…" : "Войти"}
        </button>

        <div className="mt-5 text-[11px] text-zinc-500 leading-relaxed">
          Пароль задаётся в <code className="text-zinc-300">.env</code> переменной <code className="text-zinc-300">WEB_ADMIN_PASSWORD</code>.
          При первом запуске сервер сгенерирует случайный и напишет в логи.
        </div>
      </form>
    </div>
  );
}


/**
 * Универсальная кнопка «Сохранить» с inline-индикатором.
 * Props:
 *  - onSave: async () => void — выполняет запрос, бросает на ошибке
 *  - label: текст кнопки в idle (по умолчанию «Сохранить»)
 */
function SaveButton({ onSave, label = "Сохранить" }) {
  const [state, setState] = useStateAuth("idle"); // idle | saving | ok | err
  const [err, setErr] = useStateAuth("");
  const click = async () => {
    setState("saving");
    setErr("");
    try {
      await onSave();
      setState("ok");
      setTimeout(() => setState("idle"), 1800);
    } catch (e) {
      setErr(String(e.message || e).slice(0, 120));
      setState("err");
      setTimeout(() => setState("idle"), 3500);
    }
  };
  const cls = {
    idle: "bg-indigo-500 hover:bg-indigo-600 text-white",
    saving: "bg-zinc-700 text-zinc-300 cursor-wait",
    ok: "bg-emerald-500 text-white",
    err: "bg-rose-500 text-white",
  }[state];
  const text = {
    idle: label,
    saving: "Сохраняю…",
    ok: "✓ Сохранено",
    err: "✗ Ошибка",
  }[state];
  return (
    <div className="flex flex-col items-end gap-1">
      <button
        onClick={click}
        disabled={state === "saving"}
        className={"flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-colors " + cls}
        title={err || undefined}
      >
        <Icon name="save" className="w-3.5 h-3.5" />
        {text}
      </button>
      {state === "err" && err && (
        <div className="text-[10px] text-rose-400 max-w-[300px] truncate">{err}</div>
      )}
    </div>
  );
}


/* expose */
Object.assign(window, {
  checkAuth, loginWithPassword, logoutSession, apiMutate,
  LoginScreen, SaveButton,
});
