import { useMemo, useState } from 'react';

import {
  buildTopBarNotifications,
  countUnreadTopBarNotifications,
  getTopBarCampusLabel,
  getTopBarInitials,
  getTopBarRoleLabel,
} from '@/business/top-bar/selectors';
import {
  buildTopBarSearchResults,
  type TopBarContentItem,
  type TopBarSearchResult,
} from '@/business/top-bar/search';
import {
  useCommunicationEvents,
} from '@/business/communications/hooks';
import { getScopedModules } from '@/business/app-shell/selectors';
import { useContentCatalogPayload } from '@/business/content-catalog/hooks';
import { usePolicies, usePolicyAcknowledgments } from '@/business/policies/hooks';
import { canPersistPersonalScopeResults } from '@/business/scope/selectors';
import { useSafetyProtocols } from '@/business/safety-protocols/hooks';
import { hasPermission } from '@/business/auth/permissions';
import { CONTENT_CATALOG_TYPES } from '@/shared/constants/contentCatalog';
import { MODULES } from '@/shared/constants/appData';
import type {
  ModuleId,
  SignItem,
  Strategy,
  ZoneInfo,
} from '@/shared/types/app';
import type {
  TopBarPage,
  UseTopBarPageOptions,
} from '@/business/top-bar/types';
import { useTodayZoneCheckIn } from '@/business/zone-checkin/hooks';
import { canZoneCheckIn, shouldNudgeZoneCheckIn } from '@/business/zone-checkin/selectors';
import { useScopeContext } from '@/shared/app/scope-context';

const EMPTY_STRATEGIES: readonly Strategy[] = [];
const EMPTY_SIGNS: readonly SignItem[] = [];
const EMPTY_ZONES: readonly ZoneInfo[] = [];

export function useTopBarPage({
  user,
  userRole,
  userName,
  campusInfo,
  toggleSidebar,
  setCurrentModule,
  profile,
  signOut: signOutAction,
}: UseTopBarPageOptions): TopBarPage {
  const [showProfileMenu, setShowProfileMenu] = useState(false);
  const [showNotifications, setShowNotifications] = useState(false);
  const [searchQuery, setSearchQuery] = useState('');
  const [signOutError, setSignOutError] = useState<string | null>(null);
  const { tier, ownTenant, selectedTenant } = useScopeContext();
  const canPersistPersonalResults = canPersistPersonalScopeResults(ownTenant, selectedTenant);
  const effectiveTier = selectedTenant ? selectedTenant.level : tier;
  const scopedModules = useMemo(
    () => getScopedModules(MODULES, user, effectiveTier, selectedTenant !== null),
    [effectiveTier, selectedTenant, user],
  );
  const accessibleModuleIds = useMemo(
    () => new Set(scopedModules.map((module) => module.id)),
    [scopedModules],
  );

  const canUseZoneCheckIn = canPersistPersonalResults && canZoneCheckIn(user);
  const zoneCheckIn = useTodayZoneCheckIn({ enabled: canUseZoneCheckIn });
  const needsZoneCheckIn = shouldNudgeZoneCheckIn(
    user,
    zoneCheckIn.isLoading,
    zoneCheckIn.isCheckedInToday,
  );
  const communicationEvents = useCommunicationEvents();
  const acknowledgedCommunicationEventIds = useMemo(() => new Set<string>(), []);
  const canReceivePolicyNotifications = canPersistPersonalResults && hasPermission(user, 'ACK_POLICY');
  const canReadHandbook = canReceivePolicyNotifications && accessibleModuleIds.has('handbook');
  const canReadSafetyProtocols = canReceivePolicyNotifications && accessibleModuleIds.has('safety');
  const policyAcknowledgments = usePolicyAcknowledgments(canReceivePolicyNotifications && (
    canReadHandbook || canReadSafetyProtocols
  ));
  const handbookPolicies = usePolicies(canReadHandbook);
  const safetyProtocols = useSafetyProtocols(canReadSafetyProtocols);
  const notifications = buildTopBarNotifications({
    needsZoneCheckIn,
    communicationEvents: communicationEvents.data ?? [],
    acknowledgedCommunicationEventIds,
    handbookPolicies: handbookPolicies.data ?? [],
    safetyProtocols: safetyProtocols.data ?? [],
    policyAcknowledgments: policyAcknowledgments.data ?? [],
  });

  // Header search = accessible modules (local) + their product content from the
  // content catalog. Content is fetched lazily — only once the user types, and
  // only for modules the user can access.
  const hasQuery = searchQuery.trim().length > 0;
  const moduleNameById = useMemo(
    () => new Map<ModuleId, string>(MODULES.map((module) => [module.id, module.name])),
    [],
  );

  const strategiesQuery = useContentCatalogPayload<readonly Strategy[]>(
    CONTENT_CATALOG_TYPES.classroomStrategies,
    EMPTY_STRATEGIES,
    { enabled: hasQuery && accessibleModuleIds.has('classroom') },
  );
  const signsQuery = useContentCatalogPayload<readonly SignItem[]>(
    CONTENT_CATALOG_TYPES.signLanguageItems,
    EMPTY_SIGNS,
    { enabled: hasQuery && accessibleModuleIds.has('signs') },
  );
  const zonesQuery = useContentCatalogPayload<readonly ZoneInfo[]>(
    CONTENT_CATALOG_TYPES.regulationZones,
    EMPTY_ZONES,
    { enabled: hasQuery && accessibleModuleIds.has('zones') },
  );

  const contentItems = useMemo<readonly TopBarContentItem[]>(() => {
    const items: TopBarContentItem[] = [];
    const add = (moduleId: ModuleId, id: string, label: string) => {
      items.push({ id, label, moduleId, moduleName: moduleNameById.get(moduleId) ?? '' });
    };
    strategiesQuery.payload.forEach((s) => add('classroom', `strategy-${s.id}`, s.title));
    signsQuery.payload.forEach((s) => add('signs', `sign-${s.id}`, s.word));
    zonesQuery.payload.forEach((z) => add('zones', `zone-${z.color}`, z.name));
    return items;
  }, [strategiesQuery.payload, signsQuery.payload, zonesQuery.payload, moduleNameById]);

  const searchResults = useMemo(
    () => buildTopBarSearchResults(scopedModules, user, searchQuery, contentItems),
    [scopedModules, user, searchQuery, contentItems],
  );

  function selectSearchResult(result: TopBarSearchResult) {
    setSearchQuery('');
    setCurrentModule(result.moduleId);
  }

  async function signOut() {
    setShowProfileMenu(false);
    setSignOutError(null);
    const result = await signOutAction();

    if (result.error) {
      setSignOutError(result.error);
    }
  }

  return {
    userRole,
    userName,
    campusInfo,
    profileRoleLabel: profile ? getTopBarRoleLabel(profile.role) : getTopBarRoleLabel(userRole),
    roleLabel: getTopBarRoleLabel(userRole),
    initials: getTopBarInitials(userName),
    campusLabel: getTopBarCampusLabel(campusInfo),
    showProfileMenu,
    showNotifications,
    searchQuery,
    searchResults,
    signOutError,
    notifications,
    unreadCount: countUnreadTopBarNotifications(notifications),
    toggleSidebar,
    toggleProfileMenu: () => setShowProfileMenu((current) => !current),
    closeProfileMenu: () => setShowProfileMenu(false),
    toggleNotifications: () => setShowNotifications((current) => !current),
    closeNotifications: () => setShowNotifications(false),
    setSearchQuery,
    selectSearchResult,
    signOut,
  };
}
