import { useEffect, useMemo, useState, type ReactNode } from 'react';
import { useQueryClient } from '@tanstack/react-query';

import { useScope, setActiveTenantForApi } from '@/business/scope/hooks';
import { useAuth } from '@/contexts/useAuth';
import { ScopeContext } from '@/contexts/scope-context';
import type { ActiveTenant, TenantChild } from '@/shared/types/scope';

const DRILLABLE_TIERS = new Set(['global', 'organization', 'school', 'campus']);

export function ScopeProvider({ children }: { readonly children: ReactNode }) {
  const { user } = useAuth();
  const { tier, activeTenant } = useScope(user);
  const [selectedTenant, setSelectedTenant] = useState<ActiveTenant | null>(null);
  const [prevTenantId, setPrevTenantId] = useState(activeTenant?.id);
  const queryClient = useQueryClient();

  // Reset any drill-down when the signed-in user (own tenant) changes.
  // Uses "adjust state during render" pattern to avoid cascading renders.
  if (prevTenantId !== activeTenant?.id) {
    setPrevTenantId(activeTenant?.id);
    setSelectedTenant(null);
  }

  // Sync the drill-down to the API client (request header) and refetch data so
  // pages reflect the drilled-into tenant.
  useEffect(() => {
    setActiveTenantForApi(
      selectedTenant
        ? { level: selectedTenant.level, id: selectedTenant.id }
        : null,
    );
    void queryClient.invalidateQueries();
  }, [selectedTenant, queryClient]);

  const value = useMemo(() => {
    const drillInto = (child: TenantChild) =>
      setSelectedTenant({
        level: child.level,
        id: child.id,
        name: child.name,
        logo: child.logo,
      });
    return {
      tier,
      ownTenant: activeTenant,
      selectedTenant,
      effectiveTenant: selectedTenant ?? activeTenant,
      canDrill: DRILLABLE_TIERS.has(tier),
      drillInto,
      setScopeTenant: setSelectedTenant,
      resetScope: () => setSelectedTenant(null),
    };
  }, [tier, activeTenant, selectedTenant]);

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