"use client";

import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import { authApi } from "@/lib/api/auth";
import { notificationsApi } from "@/lib/api/notifications";
import { ApiException } from "@/lib/api/client";
import type { AuthUser } from "@/lib/api/types";
import { AUTH_COOKIE, AUTH_USER_COOKIE, clientCookies } from "./cookies";

type AuthState = {
  user: AuthUser | null;
  token: string | null;
  loading: boolean;
  isAuthenticated: boolean;
  login: (email: string, password: string) => Promise<AuthUser>;
  register: (payload: {
    name: string;
    email: string;
    password: string;
    password_confirmation: string;
    phone?: string;
    otp: string;
  }) => Promise<AuthUser>;
  /** Stores a session obtained elsewhere (mobile OTP sign-in, 4.7). */
  loginWithToken: (token: string, user: AuthUser) => void;
  logout: () => Promise<void>;
  refresh: () => Promise<void>;
};

const AuthContext = createContext<AuthState | undefined>(undefined);

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<AuthUser | null>(null);
  const [token, setToken] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  // Hydrate from cookies on mount.
  useEffect(() => {
    const t = clientCookies.get(AUTH_COOKIE);
    const u = clientCookies.get(AUTH_USER_COOKIE);
    if (t) setToken(t);
    if (u) {
      try {
        setUser(JSON.parse(u) as AuthUser);
      } catch {
        clientCookies.clear(AUTH_USER_COOKIE);
      }
    }
    setLoading(false);

    /* The cached user is written at login and never again, so an account
       promoted to seller mid-session kept showing "Buyer" and the buyer-only
       menu until it logged out. Re-read it from the API once on mount. */
    if (t) {
      authApi
        .me(t)
        .then((res) => {
          if (!res?.user) return;
          const next = JSON.stringify(res.user);
          if (next !== u) {
            clientCookies.set(AUTH_USER_COOKIE, next);
            setUser(res.user);
          }
        })
        .catch(() => {
          /* Offline or an expired token: keep the cached copy. */
        });
    }
  }, []);

  const persist = useCallback((nextToken: string, nextUser: AuthUser) => {
    clientCookies.set(AUTH_COOKIE, nextToken);
    clientCookies.set(AUTH_USER_COOKIE, JSON.stringify(nextUser));
    setToken(nextToken);
    setUser(nextUser);
  }, []);

  const clearSession = useCallback(() => {
    clientCookies.clear(AUTH_COOKIE);
    clientCookies.clear(AUTH_USER_COOKIE);
    setToken(null);
    setUser(null);
  }, []);

  const login = useCallback<AuthState["login"]>(async (email, password) => {
    const res = await authApi.login({ email, password });
    persist(res.token, res.user);
    return res.user;
  }, [persist]);

  const register = useCallback<AuthState["register"]>(async (payload) => {
    const res = await authApi.register(payload);
    persist(res.token, res.user);
    return res.user;
  }, [persist]);

  const logout = useCallback(async () => {
    if (token) {
      try {
        const stored = typeof window !== "undefined" ? window.localStorage.getItem("biznie_fcm_token") : null;
        if (stored) {
          try {
            await notificationsApi.clearFcm(token, "web");
          } catch {
            /* noop */
          }
          if (typeof window !== "undefined") window.localStorage.removeItem("biznie_fcm_token");
        }
        await authApi.logout(token);
      } catch (e) {
        if (!(e instanceof ApiException) || e.status !== 401) {
          // swallow non-auth errors but still clear local session
        }
      }
    }
    clearSession();
  }, [token, clearSession]);

  const refresh = useCallback(async () => {
    if (!token) return;
    try {
      const res = await authApi.me(token);
      setUser(res.user);
      clientCookies.set(AUTH_USER_COOKIE, JSON.stringify(res.user));
    } catch (e) {
      if (e instanceof ApiException && e.status === 401) clearSession();
    }
  }, [token, clearSession]);

  const value = useMemo<AuthState>(
    () => ({
      user,
      token,
      loading,
      isAuthenticated: !!token && !!user,
      login,
      loginWithToken: persist,
      register,
      logout,
      refresh,
    }),
    [user, token, loading, login, register, logout, refresh, persist]
  );

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}

export function useAuth(): AuthState {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used within <AuthProvider>");
  return ctx;
}
