/* global React, window */
const { createContext, useContext, useState, useEffect, useCallback } = React;

// ВАЖНО: на проде window.API_BASE === "" (тот же домен). Пустая строка «ложная»,
// поэтому через || она ошибочно подменялась на localhost - проверяем именно тип.
const API_BASE = (typeof window.API_BASE === "string") ? window.API_BASE : "http://localhost:4000";

async function apiFetch(path, opts = {}) {
  const res = await fetch(API_BASE + path, {
    credentials: "include",
    headers: { "Content-Type": "application/json", ...(opts.headers || {}) },
    ...opts,
  });
  let body = null;
  try { body = await res.json(); } catch { /* 204 / non-json */ }
  if (!res.ok) {
    const err = new Error((body && body.error) || "request_failed");
    err.status = res.status;
    err.data = body;
    throw err;
  }
  return body;
}

const api = {
  requestCode: email => apiFetch("/auth/request-code", { method: "POST", body: JSON.stringify({ email }) }),
  register: data => apiFetch("/auth/register", { method: "POST", body: JSON.stringify(data) }),
  login:    data => apiFetch("/auth/login",    { method: "POST", body: JSON.stringify(data) }),
  google:   credential => apiFetch("/auth/google", { method: "POST", body: JSON.stringify({ credential }) }),
  logout:   ()   => apiFetch("/auth/logout",   { method: "POST" }),
  me:       ()   => apiFetch("/me"),
  updateMe: data => apiFetch("/me",            { method: "PATCH", body: JSON.stringify(data) }),
  changePassword: data => apiFetch("/password/change", { method: "POST", body: JSON.stringify(data) }),
  forgotPassword: email => apiFetch("/password/forgot", { method: "POST", body: JSON.stringify({ email }) }),
  resetPassword:  data  => apiFetch("/password/reset",  { method: "POST", body: JSON.stringify(data) }),
};

const AuthContext = createContext(null);

function AuthProvider({ children }) {
  // undefined = ещё не проверили; null = гость; объект = вошёл
  const [user, setUser] = useState(undefined);
  const [serverReachable, setServerReachable] = useState(true);

  useEffect(() => {
    let cancelled = false;
    api.me()
      .then(r => { if (!cancelled) { setUser(r.user); setServerReachable(true); } })
      .catch(err => {
        if (cancelled) return;
        if (err.status === 401) setUser(null);
        else { setUser(null); setServerReachable(false); }
      });
    return () => { cancelled = true; };
  }, []);

  const login = useCallback(async data => {
    const r = await api.login(data); setUser(r.user); return r.user;
  }, []);

  const register = useCallback(async data => {
    const r = await api.register(data); setUser(r.user); return r.user;
  }, []);

  const loginWithGoogle = useCallback(async credential => {
    const r = await api.google(credential); setUser(r.user); return r.user;
  }, []);

  const logout = useCallback(async () => {
    try { await api.logout(); } catch { /* всё равно очищаем локально */ }
    setUser(null);
  }, []);

  const refresh = useCallback(async () => {
    const r = await api.me(); setUser(r.user); return r.user;
  }, []);

  const value = {
    user,
    isLoading: user === undefined,
    isAuthed: !!user,
    serverReachable,
    login, register, loginWithGoogle, logout, refresh, setUser,
  };
  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
  return ctx;
}

// Преобразование кода ошибки бекенда в человеческий текст
const ERROR_RU = {
  validation_failed:        "Проверьте корректность полей.",
  email_taken:              "Такой email уже зарегистрирован.",
  invalid_credentials:      "Неверный email или пароль.",
  unauthenticated:          "Нужно войти в аккаунт.",
  invalid_current_password: "Текущий пароль введён неверно.",
  same_password:            "Новый пароль совпадает со старым.",
  invalid_token:            "Ссылка недействительна.",
  expired_token:            "Срок действия ссылки истёк - запросите новую.",
  request_failed:           "Что-то пошло не так. Попробуйте ещё раз.",
  code_not_requested:       "Сначала запросите код на email.",
  invalid_code:             "Неверный код. Проверьте письмо.",
  expired_code:             "Код истёк - запросите новый.",
  too_many_attempts:        "Слишком много попыток - запросите новый код.",
  google_auth_failed:       "Не удалось войти через Google. Попробуйте ещё раз.",
  google_not_configured:    "Вход через Google пока не настроен.",
};

function humanError(err) {
  const code = err && (err.message || err.data?.error);
  return ERROR_RU[code] || "Что-то пошло не так. Попробуйте ещё раз.";
}

Object.assign(window, { api, AuthProvider, useAuth, humanError, API_BASE });
