// Auth state for the self-hosted backend. Stores JWT + user in localStorage,
// exposes a React context and a small imperative API used by backend-client.ts.

import { createContext, useContext, useEffect, useState, type ReactNode } from "react";
import { API_BASE_URL } from "./backend-client";

export interface AuthUser {
  id: string;
  email: string;
  first_name?: string | null;
  last_name?: string | null;
  role: "user" | "admin";
  impersonating?: { id: string; email: string; first_name?: string | null; last_name?: string | null } | null;
}

export function displayName(u: { first_name?: string | null; last_name?: string | null; email: string } | null | undefined): string {
  if (!u) return "";
  const full = `${u.first_name ?? ""} ${u.last_name ?? ""}`.trim();
  return full || u.email;
}

const TOKEN_KEY = "delta-terminal-token";
const USER_KEY = "delta-terminal-user";
const ADMIN_TOKEN_KEY = "delta-terminal-admin-token"; // saved when impersonating so we can restore

export function getToken(): string | null {
  return typeof window !== "undefined" ? window.localStorage.getItem(TOKEN_KEY) : null;
}
function setToken(t: string | null) {
  if (typeof window === "undefined") return;
  if (t) window.localStorage.setItem(TOKEN_KEY, t);
  else window.localStorage.removeItem(TOKEN_KEY);
  window.dispatchEvent(new Event("delta-auth-changed"));
}
function readUser(): AuthUser | null {
  if (typeof window === "undefined") return null;
  try {
    const raw = window.localStorage.getItem(USER_KEY);
    return raw ? (JSON.parse(raw) as AuthUser) : null;
  } catch {
    return null;
  }
}
function writeUser(u: AuthUser | null) {
  if (typeof window === "undefined") return;
  if (u) window.localStorage.setItem(USER_KEY, JSON.stringify(u));
  else window.localStorage.removeItem(USER_KEY);
}

async function api<T>(path: string, init: RequestInit = {}, token?: string | null): Promise<T> {
  const t = token ?? getToken();
  const res = await fetch(`${API_BASE_URL}${path}`, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      ...(t ? { Authorization: `Bearer ${t}` } : {}),
      ...(init.headers ?? {}),
    },
  });
  const body = await res.json().catch(() => ({}));
  if (!res.ok) throw new Error(body.error ?? `${res.status}`);
  return body as T;
}

export const authApi = {
  register(email: string, password: string, firstName?: string, lastName?: string) {
    return api<{ token: string; user: AuthUser }>("/auth/register", {
      method: "POST",
      body: JSON.stringify({ email, password, first_name: firstName, last_name: lastName }),
    });
  },
  login(email: string, password: string) {
    return api<{ token: string; user: AuthUser }>("/auth/login", {
      method: "POST",
      body: JSON.stringify({ email, password }),
    });
  },
  me(token?: string) {
    return api<AuthUser>("/auth/me", { method: "GET" }, token);
  },
  listUsers() {
    return api<
      Array<{
        id: string;
        email: string;
        first_name?: string | null;
        last_name?: string | null;
        role: string;
        status: string;
        created_at: string;
        last_login_at: string | null;
        delta_linked: boolean;
      }>
    
    >("/admin/users");
  },
  impersonate(userId: string) {
    return api<{ token: string; user: AuthUser }>(`/admin/impersonate/${userId}`, { method: "POST" });
  },
};

// ---------------- Context ----------------

interface AuthCtx {
  user: AuthUser | null;
  loading: boolean;
  signIn: (email: string, password: string) => Promise<void>;
  signUp: (email: string, password: string, firstName?: string, lastName?: string) => Promise<void>;
  signOut: () => void;
  impersonate: (userId: string) => Promise<void>;
  stopImpersonation: () => void;
}

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

export function AuthProvider({ children }: { children: ReactNode }) {
  // DEV BYPASS: if no token exists, seed a mock super-admin so the app is usable
  // without a running backend. Remove this block to restore real auth.
  const BYPASS_USER: AuthUser = {
    id: "dev-admin",
    email: "ds75279@gmail.com",
    first_name: "Deepak",
    last_name: "Sharma",
    role: "admin",
    impersonating: null,
  };
  if (typeof window !== "undefined") {
    const existing = readUser();
    if (!getToken() && !existing) {
      writeUser(BYPASS_USER);
      window.localStorage.setItem(TOKEN_KEY, "dev-bypass-token");
    } else if (existing && existing.email === BYPASS_USER.email && (!existing.first_name || !existing.last_name)) {
      writeUser({ ...existing, first_name: BYPASS_USER.first_name, last_name: BYPASS_USER.last_name });
    }
  }

  const [user, setUser] = useState<AuthUser | null>(readUser() ?? BYPASS_USER);
  const [loading, setLoading] = useState<boolean>(false);

  useEffect(() => {
    let alive = true;
    const tok = getToken();
    if (!tok || tok === "dev-bypass-token") {
      setLoading(false);
      return;
    }
    authApi
      .me()
      .then((u) => {
        if (!alive) return;
        writeUser(u);
        setUser(u);
      })
      .catch(() => {
        setToken(null);
        writeUser(null);
        setUser(null);
      })
      .finally(() => alive && setLoading(false));
    return () => {
      alive = false;
    };
  }, []);

  useEffect(() => {
    const onChange = () => setUser(readUser());
    window.addEventListener("delta-auth-changed", onChange);
    return () => window.removeEventListener("delta-auth-changed", onChange);
  }, []);

  const ctx: AuthCtx = {
    user,
    loading,
    async signIn(email, password) {
      const { token, user: u } = await authApi.login(email, password);
      setToken(token);
      writeUser(u);
      setUser(u);
    },
    async signUp(email, password, firstName, lastName) {
      const { token, user: u } = await authApi.register(email, password, firstName, lastName);
      setToken(token);
      writeUser(u);
      setUser(u);
    },
    signOut() {
      setToken(null);
      writeUser(null);
      window.localStorage.removeItem(ADMIN_TOKEN_KEY);
      setUser(null);
    },
    async impersonate(userId) {
      const adminToken = getToken();
      if (!adminToken) throw new Error("Not signed in");
      const { token } = await authApi.impersonate(userId);
      window.localStorage.setItem(ADMIN_TOKEN_KEY, adminToken);
      setToken(token);
      const me = await authApi.me(token);
      writeUser(me);
      setUser(me);
    },
    stopImpersonation() {
      const adminToken = window.localStorage.getItem(ADMIN_TOKEN_KEY);
      if (!adminToken) return;
      window.localStorage.removeItem(ADMIN_TOKEN_KEY);
      setToken(adminToken);
      authApi.me(adminToken).then((u) => {
        writeUser(u);
        setUser(u);
      });
    },
  };

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

export function useAuth() {
  const c = useContext(Ctx);
  if (!c) throw new Error("useAuth outside AuthProvider");
  return c;
}
