import React, { createContext, useContext, useState, useEffect, useCallback } from "react";
import { AuthProvider as OidcAuthProvider, useAuth as useOidcAuth } from "react-oidc-context";

const AUTH_MODE = import.meta.env.VITE_AUTH_MODE ?? "dev";

// ─── Shared user type ─────────────────────────────────────────────────────────

export interface AuthUser {
  id: string;
  email: string;
  name: string;
  roles: string[];
  token: string;
}

// ─── Dev mode auth ────────────────────────────────────────────────────────────

interface DevAuthContextValue {
  user: AuthUser | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  login: () => void;
  logout: () => void;
}

const DevAuthContext = createContext<DevAuthContextValue | null>(null);

const DEV_USER: AuthUser = {
  id: "dev-user",
  email: "dev@veylant.local",
  name: "Dev Admin",
  roles: ["admin"],
  token: "dev-token",
};

function DevAuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<AuthUser | null>(() => {
    return sessionStorage.getItem("dev-authed") ? DEV_USER : null;
  });

  const login = useCallback(() => {
    sessionStorage.setItem("dev-authed", "1");
    setUser(DEV_USER);
  }, []);

  const logout = useCallback(() => {
    sessionStorage.removeItem("dev-authed");
    setUser(null);
  }, []);

  return (
    <DevAuthContext.Provider
      value={{ user, isLoading: false, isAuthenticated: !!user, login, logout }}
    >
      {children}
    </DevAuthContext.Provider>
  );
}

// ─── OIDC mode adapter ────────────────────────────────────────────────────────

interface UnifiedAuthContextValue {
  user: AuthUser | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  login: () => void;
  logout: () => void;
}

const UnifiedAuthContext = createContext<UnifiedAuthContextValue | null>(null);

function OidcAdapter({ children }: { children: React.ReactNode }) {
  const auth = useOidcAuth();

  const user: AuthUser | null = auth.user
    ? {
        id: auth.user.profile.sub,
        email: auth.user.profile.email ?? "",
        name: auth.user.profile.name ?? auth.user.profile.email ?? "",
        roles: (auth.user.profile as Record<string, unknown>)["realm_access"]
          ? ((auth.user.profile as Record<string, unknown>)["realm_access"] as { roles: string[] }).roles
          : [],
        token: auth.user.access_token,
      }
    : null;

  return (
    <UnifiedAuthContext.Provider
      value={{
        user,
        isLoading: auth.isLoading,
        isAuthenticated: auth.isAuthenticated,
        login: () => void auth.signinRedirect(),
        logout: () => void auth.signoutRedirect(),
      }}
    >
      {children}
    </UnifiedAuthContext.Provider>
  );
}

// ─── Public hook ──────────────────────────────────────────────────────────────

export function useAuth(): UnifiedAuthContextValue {
  if (AUTH_MODE === "dev") {
    // eslint-disable-next-line react-hooks/rules-of-hooks
    const ctx = useContext(DevAuthContext);
    if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
    return ctx;
  }
  // eslint-disable-next-line react-hooks/rules-of-hooks
  const ctx = useContext(UnifiedAuthContext);
  if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
  return ctx;
}

// ─── Root AuthProvider ────────────────────────────────────────────────────────

const oidcConfig = {
  authority: import.meta.env.VITE_KEYCLOAK_URL ?? "http://localhost:8080/realms/veylant",
  client_id: "veylant-dashboard",
  redirect_uri: `${window.location.origin}/callback`,
  scope: "openid profile email",
  onSigninCallback: () => {
    window.history.replaceState({}, document.title, window.location.pathname);
  },
};

export function AuthProvider({ children }: { children: React.ReactNode }) {
  if (AUTH_MODE === "dev") {
    return <DevAuthProvider>{children}</DevAuthProvider>;
  }

  return (
    <OidcAuthProvider {...oidcConfig}>
      <OidcAdapter>
        <UnifiedAuthContext.Consumer>
          {(ctx) =>
            ctx ? (
              <UnifiedAuthContext.Provider value={ctx}>{children}</UnifiedAuthContext.Provider>
            ) : null
          }
        </UnifiedAuthContext.Consumer>
      </OidcAdapter>
    </OidcAuthProvider>
  );
}

// Token accessor for API client (outside React tree)
let _getToken: (() => string | null) | null = null;

export function setTokenAccessor(fn: () => string | null) {
  _getToken = fn;
}

export function getToken(): string | null {
  return _getToken ? _getToken() : null;
}

// Hook to register token accessor in context
export function useRegisterTokenAccessor() {
  const auth = useAuth();
  useEffect(() => {
    setTokenAccessor(() => auth.user?.token ?? null);
  }, [auth.user]);
}
