// Auth context: SecureStore-backed session, biometric unlock, refresh flow.
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import * as LocalAuth from "expo-local-authentication";
import { api, getRefreshToken, getToken, setToken, User } from "@/api/client";
import * as SecureStore from "expo-secure-store";

const BIOMETRIC_KEY = "delta-terminal-biometric";

type State = {
  user: User | null;
  loading: boolean;
  locked: boolean; // needs biometric unlock
  biometricEnabled: boolean;
};
type Ctx = State & {
  signIn: (email: string, password: string) => Promise<void>;
  register: (body: { email: string; password: string; first_name?: string; last_name?: string }) => Promise<void>;
  signOut: () => Promise<void>;
  unlock: () => Promise<boolean>;
  setBiometric: (on: boolean) => Promise<void>;
};

const AuthCtx = createContext<Ctx | null>(null);

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [state, setState] = useState<State>({
    user: null, loading: true, locked: false, biometricEnabled: false,
  });

  const loadMe = useCallback(async () => {
    try { const user = await api.me(); return user; } catch { return null; }
  }, []);

  useEffect(() => {
    (async () => {
      const [tok, bioRaw] = await Promise.all([
        getToken(),
        SecureStore.getItemAsync(BIOMETRIC_KEY),
      ]);
      const bio = bioRaw === "1";
      if (!tok) { setState({ user: null, loading: false, locked: false, biometricEnabled: bio }); return; }
      // Have a token — if biometric is enabled, gate behind unlock.
      if (bio) {
        setState({ user: null, loading: false, locked: true, biometricEnabled: true });
        return;
      }
      const user = await loadMe();
      setState({ user, loading: false, locked: false, biometricEnabled: bio });
    })();
  }, [loadMe]);

  const signIn = useCallback(async (email: string, password: string) => {
    const res = await api.login(email, password);
    await setToken(res.token, res.refresh_token ?? res.token);
    setState((s) => ({ ...s, user: res.user, locked: false, loading: false }));
  }, []);

  const register = useCallback(async (body: { email: string; password: string; first_name?: string; last_name?: string }) => {
    const res = await api.register(body);
    await setToken(res.token, res.refresh_token ?? res.token);
    setState((s) => ({ ...s, user: res.user, locked: false, loading: false }));
  }, []);

  const signOut = useCallback(async () => {
    await setToken(null, null);
    setState((s) => ({ ...s, user: null, locked: false }));
  }, []);

  const unlock = useCallback(async () => {
    const has = await LocalAuth.hasHardwareAsync();
    const enrolled = await LocalAuth.isEnrolledAsync();
    if (!has || !enrolled) {
      // Fallback: no biometric available → just proceed with stored token.
      const user = await loadMe();
      setState((s) => ({ ...s, user, locked: false }));
      return true;
    }
    const result = await LocalAuth.authenticateAsync({
      promptMessage: "Unlock Delta Terminal",
      fallbackLabel: "Use password",
      disableDeviceFallback: false,
    });
    if (!result.success) return false;
    // Refresh JWT silently.
    const refresh = await getRefreshToken();
    if (refresh) {
      try {
        const res = await api.refresh(refresh);
        await setToken(res.token, res.refresh_token ?? res.token);
      } catch { /* fall through to /auth/me */ }
    }
    const user = await loadMe();
    if (!user) return false;
    setState((s) => ({ ...s, user, locked: false }));
    return true;
  }, [loadMe]);

  const setBiometric = useCallback(async (on: boolean) => {
    await SecureStore.setItemAsync(BIOMETRIC_KEY, on ? "1" : "0");
    setState((s) => ({ ...s, biometricEnabled: on }));
  }, []);

  const value = useMemo<Ctx>(() => ({ ...state, signIn, register, signOut, unlock, setBiometric }),
    [state, signIn, register, signOut, unlock, setBiometric]);

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

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

export function displayName(u: User | null) {
  if (!u) return "";
  const n = [u.first_name, u.last_name].filter(Boolean).join(" ").trim();
  return n || u.email;
}
