import AsyncStorage from "@react-native-async-storage/async-storage";
import { ApiError, createApi, type TokenStore } from "@sheikbras/api-client";
import * as SecureStore from "expo-secure-store";
import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from "react";

export interface AuthUser { name: string; email: string }
/** Contrato do serviço de conta usado pelas telas. Duas implementações: API real (com EXPO_PUBLIC_API_URL) ou demonstração local. */
export interface AuthService {
  register(v: { nome: string; email: string; senha: string }): Promise<AuthUser>;
  login(email: string, senha: string, codigo?: string): Promise<AuthUser>;
  logout(): Promise<void>;
  session(): Promise<AuthUser | null>;
  forgotPassword(email: string): Promise<void>;
}
export const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "";

/* ---- API real: tokens no cofre do aparelho (Keychain/Keystore), nunca no AsyncStorage ---- */
const KEY = "sb_tokens";
export const secureTokenStore: TokenStore = {
  async get() { try { const v = await SecureStore.getItemAsync(KEY); return v ? JSON.parse(v) : null; } catch { return null; } },
  async set(t) { try { if (t) await SecureStore.setItemAsync(KEY, JSON.stringify(t)); else await SecureStore.deleteItemAsync(KEY); } catch { /* cofre indisponível */ } },
};
export function createApiAuth(baseUrl = API_URL, store: TokenStore = secureTokenStore, onExpired?: () => void) {
  const api = createApi({ baseUrl, store, onSessionExpired: onExpired });
  const svc: AuthService = {
    async register(v) { const r = await api.auth.register({ ...v, aceite: true }); return { name: r.user.name, email: r.user.email }; },
    async login(email, senha, codigo) { const r = await api.auth.login({ email, senha, codigo }); return { name: r.user.name, email: r.user.email }; },
    logout: () => api.auth.logout(),
    async session() { if (!(await api.hasSession())) return null; try { const me = await api.me.get(); return { name: me.name, email: me.email }; } catch { return null; } },
    forgotPassword: async (email) => { try { await api.auth.forgotPassword(email); } catch (e) { if (e instanceof ApiError && e.code === "RATE_LIMITED") throw e; } },
  };
  return { api, svc };
}

/* ---- demonstração local (NÃO é segurança) ---- */
const demoHash = (s: string) => { let h = 2166136261; for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); } return (h >>> 0).toString(16); };
const norm = (e: string) => e.trim().toLowerCase();
export const demoAuth: AuthService = {
  async register({ nome, email, senha }) {
    const users = JSON.parse((await AsyncStorage.getItem("sb_users")) ?? "{}"); const k = norm(email);
    if (users[k]) throw new ApiError("EMAIL_TAKEN", "Já existe uma conta com este e-mail.", 409);
    users[k] = { name: nome.trim(), h: demoHash(senha) }; await AsyncStorage.setItem("sb_users", JSON.stringify(users));
    const u = { name: nome.trim(), email: k }; await AsyncStorage.setItem("sb_session", JSON.stringify(u)); return u;
  },
  async login(email, senha) {
    const users = JSON.parse((await AsyncStorage.getItem("sb_users")) ?? "{}"); const u = users[norm(email)];
    if (!u || u.h !== demoHash(senha)) throw new ApiError("INVALID_CREDENTIALS", "E-mail ou senha incorretos.", 401);
    const s = { name: u.name as string, email: norm(email) }; await AsyncStorage.setItem("sb_session", JSON.stringify(s)); return s;
  },
  async logout() { await AsyncStorage.removeItem("sb_session"); },
  async session() { const v = await AsyncStorage.getItem("sb_session"); return v ? (JSON.parse(v) as AuthUser) : null; },
  async forgotPassword() { /* demonstração: sem e-mail */ },
};

interface Auth { user: AuthUser | null; ready: boolean; apiEnabled: boolean; register: AuthService["register"]; login: AuthService["login"]; logout: () => Promise<void>; forgotPassword: AuthService["forgotPassword"] }
const Ctx = createContext<Auth | null>(null);
export function AuthProvider({ children, service, initialUser }: { children: ReactNode; service?: AuthService; initialUser?: AuthUser | null }) {
  const [user, setUser] = useState<AuthUser | null>(initialUser ?? null); const [ready, setReady] = useState(initialUser !== undefined);
  const svc = useMemo(() => service ?? (API_URL ? createApiAuth(API_URL, secureTokenStore, () => setUser(null)).svc : demoAuth), [service]);
  useEffect(() => { if (initialUser !== undefined) return; svc.session().then((u) => { setUser(u); setReady(true); }).catch(() => setReady(true)); }, [svc, initialUser]);
  const value: Auth = { user, ready, apiEnabled: !!API_URL && !service,
    register: async (v) => { const u = await svc.register(v); setUser(u); return u; },
    login: async (e, s, c) => { const u = await svc.login(e, s, c); setUser(u); return u; },
    logout: async () => { await svc.logout(); setUser(null); }, forgotPassword: (e) => svc.forgotPassword(e) };
  return <Ctx.Provider value={value}>{children}</Ctx.Provider>;
}
export function useAuth(): Auth { const a = useContext(Ctx); if (!a) throw new Error("useAuth fora do AuthProvider"); return a; }
