import type { ReactNode } from "react";
import { createContext, startTransition, useContext, useEffect, useState } from "react";

import type { TenantContext } from "@platform-types";

import {
  type AuthenticatedUser,
  bootstrapSuperAdmin,
  fetchAuthProfile,
  impersonateTenant,
  loginToPortal,
  logoutFromPortal,
  type AuthPayload,
  type AuthResponse,
  type BootstrapSuperAdminRequest,
  type PlatformAdminContext
} from "../lib/api";
import {
  clearAdminSessionToken,
  clearSessionToken,
  getStoredAdminSessionToken,
  getStoredSessionToken,
  storeAdminSessionToken,
  storeSessionToken
} from "../lib/session";
import { portalRuntimeConfig } from "../config/runtime";

type SessionStatus = "loading" | "authenticated" | "unauthenticated";

interface PortalSessionContextValue {
  status: SessionStatus;
  sessionToken: string | null;
  tenantContext: TenantContext | null;
  currentUser: AuthenticatedUser | null;
  platformAdmin: PlatformAdminContext | null;
  login: (payload: AuthPayload) => Promise<AuthResponse>;
  bootstrap: (payload: BootstrapSuperAdminRequest) => Promise<AuthResponse>;
  logout: () => Promise<void>;
  refresh: () => Promise<void>;
  impersonate: (tenantId: string) => Promise<void>;
  returnToAdmin: () => Promise<void>;
  hasStoredAdminSession: boolean;
}

const PortalSessionContext = createContext<PortalSessionContextValue | undefined>(undefined);

function applyAuthenticatedState(
  response: AuthResponse,
  setStatus: (value: SessionStatus) => void,
  setSessionToken: (value: string | null) => void,
  setTenantContext: (value: TenantContext | null) => void,
  setCurrentUser: (value: AuthenticatedUser | null) => void,
  setPlatformAdmin: (value: PlatformAdminContext | null) => void
) {
  storeSessionToken(response.session_token);
  startTransition(() => {
    setStatus("authenticated");
    setSessionToken(response.session_token);
    setTenantContext(response.tenant_context);
    setCurrentUser(response.current_user);
    setPlatformAdmin(response.platform_admin ?? null);
  });
}

export function PortalSessionProvider({ children }: { children: ReactNode }) {
  const [status, setStatus] = useState<SessionStatus>("loading");
  const [sessionToken, setSessionToken] = useState<string | null>(null);
  const [tenantContext, setTenantContext] = useState<TenantContext | null>(null);
  const [currentUser, setCurrentUser] = useState<AuthenticatedUser | null>(null);
  const [platformAdmin, setPlatformAdmin] = useState<PlatformAdminContext | null>(null);

  async function refresh() {
    const token = getStoredSessionToken();
    if (!token) {
      startTransition(() => {
        setStatus("unauthenticated");
        setSessionToken(null);
        setTenantContext(null);
        setCurrentUser(null);
        setPlatformAdmin(null);
      });
      return;
    }

    try {
      const response = await fetchAuthProfile(portalRuntimeConfig.apiHubBaseUrl);
      applyAuthenticatedState(response, setStatus, setSessionToken, setTenantContext, setCurrentUser, setPlatformAdmin);
    } catch {
      clearSessionToken();
      startTransition(() => {
        setStatus("unauthenticated");
        setSessionToken(null);
        setTenantContext(null);
        setCurrentUser(null);
        setPlatformAdmin(null);
      });
    }
  }

  useEffect(() => {
    void refresh();
  }, []);

  async function login(payload: AuthPayload) {
    const response = await loginToPortal(portalRuntimeConfig.apiHubBaseUrl, payload);
    clearAdminSessionToken();
    applyAuthenticatedState(response, setStatus, setSessionToken, setTenantContext, setCurrentUser, setPlatformAdmin);
    return response;
  }

  async function bootstrap(payload: BootstrapSuperAdminRequest) {
    const response = await bootstrapSuperAdmin(portalRuntimeConfig.apiHubBaseUrl, payload);
    clearAdminSessionToken();
    applyAuthenticatedState(response, setStatus, setSessionToken, setTenantContext, setCurrentUser, setPlatformAdmin);
    return response;
  }

  async function impersonate(tenantId: string) {
    const currentToken = getStoredSessionToken();
    if (currentToken) {
      storeAdminSessionToken(currentToken);
    }

    const response = await impersonateTenant(portalRuntimeConfig.apiHubBaseUrl, tenantId);
    applyAuthenticatedState(response, setStatus, setSessionToken, setTenantContext, setCurrentUser, setPlatformAdmin);
  }

  async function returnToAdmin() {
    const adminToken = getStoredAdminSessionToken();
    if (!adminToken) {
      throw new Error("Sessione admin originale non disponibile.");
    }

    storeSessionToken(adminToken);
    clearAdminSessionToken();
    await refresh();
  }

  async function logout() {
    try {
      await logoutFromPortal(portalRuntimeConfig.apiHubBaseUrl);
    } catch {
      // Ignore logout transport failures and clear client state anyway.
    }

    clearAdminSessionToken();
    clearSessionToken();
    startTransition(() => {
      setStatus("unauthenticated");
      setSessionToken(null);
      setTenantContext(null);
      setCurrentUser(null);
      setPlatformAdmin(null);
    });
  }

  return (
    <PortalSessionContext.Provider
      value={{
        status,
        sessionToken,
        tenantContext,
        currentUser,
        platformAdmin,
        login,
        bootstrap,
        logout,
        refresh,
        impersonate,
        returnToAdmin,
        hasStoredAdminSession: Boolean(getStoredAdminSessionToken())
      }}
    >
      {children}
    </PortalSessionContext.Provider>
  );
}

export function usePortalSession(): PortalSessionContextValue {
  const context = useContext(PortalSessionContext);
  if (!context) {
    throw new Error("usePortalSession deve essere usato dentro PortalSessionProvider");
  }

  return context;
}
