/**
 * Who is signed in, fetched once.
 *
 * Before this, five components each ran their own `useQuery(['me'])`. React
 * Query deduplicated the *request*, so it looked harmless, but it meant every
 * consumer separately restated the response shape — and they had already
 * diverged: some declared `{ id, name }`, some added `isPlatformAdmin`, none
 * carried `permissions`. A control that cannot see the grants cannot be gated
 * on them, which is why navigation showed everyone pages that answer 403.
 *
 * The query key stays `['me']` so anything still fetching it directly, and any
 * `invalidateQueries` already written against it, keeps working.
 */
import { createContext, useContext, type ReactNode } from 'react';
import { useQuery, type UseQueryResult } from '@tanstack/react-query';
import type { PermissionGrant, Team, TeamRole } from '@pig/core';
import { get } from './api';

export interface Identity {
  id: string;
  email: string;
  name: string;
  isPlatformAdmin: boolean;
  teams: { team: Team; role: TeamRole }[];
  /** Effective grants, resolved server-side. Never re-derive them here. */
  permissions: PermissionGrant[];
  /** How this request authenticated — a session, or an API key. */
  via: string;
}

export const IDENTITY_QUERY_KEY = ['me'] as const;

export function useIdentityQuery(): UseQueryResult<Identity, unknown> {
  return useQuery({
    queryKey: IDENTITY_QUERY_KEY,
    queryFn: () => get<Identity>('/api/me'),
  });
}

const IdentityContext = createContext<Identity | null>(null);

export function IdentityProvider({
  identity,
  children,
}: {
  identity: Identity;
  children: ReactNode;
}) {
  return <IdentityContext.Provider value={identity}>{children}</IdentityContext.Provider>;
}

/**
 * The signed-in person. Throws outside the provider rather than returning
 * `undefined`, because every consumer sits inside the auth gate and a silent
 * `undefined` reads to `can()` as "no permissions" — a denial that looks like
 * a policy decision instead of a missing provider.
 */
export function useIdentity(): Identity {
  const identity = useContext(IdentityContext);
  if (!identity) throw new Error('useIdentity must be used inside an IdentityProvider.');
  return identity;
}

/** For code that may render outside the gate (the sign-in screens). */
export function useOptionalIdentity(): Identity | null {
  return useContext(IdentityContext);
}
