import { useMemo, useState } from 'react';
import { useQuery } from '@tanstack/react-query';

import { listCampusAttendanceSummaries } from '@/shared/api/campusAttendance';
import { listFrameEntries } from '@/shared/api/frame';
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 {
  normalizeSignLanguageItems,
  selectSignLanguageSignOfWeek,
} from '@/business/sign-language/selectors';
import {
  useEsaFundingPolicyDocument,
  usePolicies,
  usePolicyAcknowledgments,
} from '@/business/policies/hooks';
import { useCurrentPersonalityResult } from '@/business/personality/queryHooks';
import { useMySafetyQuizStatus } from '@/business/safety-quiz/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 { PERSONALITY_QUIZ_KINDS } from '@/shared/constants/personality';
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';
import { getCurrentSafetyQuizWeek } from '@/business/safety-quiz/selectors';
import { useLearnedSignsProgress } from '@/business/user-progress/hooks';
import type { DashboardSignOfWeek } from '@/shared/types/dashboard';
import { toWeekStartIso } from '@/shared/business/week';

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(
    canUseZoneCheckIn ? user : null,
    zoneCheckIn.isLoading,
    zoneCheckIn.isCheckedInToday,
  );
  const canReceiveSafetyQuizNotification = canPersistPersonalResults
    && hasPermission(user, 'TAKE_QUIZ')
    && accessibleModuleIds.has('qbs')
    && (effectiveTier === 'school' || effectiveTier === 'campus' || effectiveTier === 'class');
  const safetyQuizWeek = getCurrentSafetyQuizWeek(new Date());
  const today = new Date().toISOString().split('T')[0] ?? '';
  const safetyQuizStatus = useMySafetyQuizStatus(
    safetyQuizWeek,
    canReceiveSafetyQuizNotification,
  );
  const needsSafetyQuiz = canReceiveSafetyQuizNotification
    && !safetyQuizStatus.isLoading
    && safetyQuizStatus.data?.completed !== true;
  const canReceiveSignOfWeekNotification = canPersistPersonalResults
    && accessibleModuleIds.has('signs');
  const canManageWeeklySignSelection = hasPermission(user, 'MANAGE_CONTENT_CATALOG')
    && accessibleModuleIds.has('signs')
    && effectiveTier === 'organization';
  const signOfWeekQuery = useContentCatalogPayload<DashboardSignOfWeek | null>(
    CONTENT_CATALOG_TYPES.dashboardSignOfWeek,
    null,
    { enabled: canReceiveSignOfWeekNotification || canManageWeeklySignSelection },
  );
  const learnedSigns = useLearnedSignsProgress({ enabled: canReceiveSignOfWeekNotification });
  const canManageWeeklyFrame = hasPermission(user, 'MANAGE_FRAME')
    && accessibleModuleIds.has('frame');
  const frameContentQuery = useQuery({
    queryKey: ['top-bar-weekly-frame-content', safetyQuizWeek],
    enabled: canManageWeeklyFrame,
    queryFn: async () => {
      const response = await listFrameEntries({
        startDate: safetyQuizWeek,
        endDate: safetyQuizWeek,
      });
      return response.rows;
    },
  });
  const canManageDailyAttendance = hasPermission(user, 'FILL_ATTENDANCE')
    && accessibleModuleIds.has('attendance');
  const attendanceCampusKey =
    effectiveTier === 'campus' || effectiveTier === 'class'
      ? campusInfo?.id
      : undefined;
  const attendanceContentQuery = useQuery({
    queryKey: ['top-bar-daily-attendance-content', today, attendanceCampusKey ?? null, effectiveTier],
    enabled: canManageDailyAttendance && Boolean(today) && (
      effectiveTier === 'organization'
      || effectiveTier === 'school'
      || Boolean(attendanceCampusKey)
    ),
    queryFn: async () => {
      const response = await listCampusAttendanceSummaries({
        ...(attendanceCampusKey ? { campusKey: attendanceCampusKey } : {}),
        startDate: today,
        endDate: today,
      });
      return response.rows;
    },
  });
  const canReceiveEmotionalIntelligenceNotifications = canPersistPersonalResults
    && hasPermission(user, 'TAKE_QUIZ')
    && accessibleModuleIds.has('ei');
  const selfAssessmentStatus = useCurrentPersonalityResult(
    PERSONALITY_QUIZ_KINDS.selfAssessment,
    canReceiveEmotionalIntelligenceNotifications,
  );
  const personalityQuizStatus = useCurrentPersonalityResult(
    PERSONALITY_QUIZ_KINDS.personalityType,
    canReceiveEmotionalIntelligenceNotifications,
  );
  const needsEiSelfAssessment = canReceiveEmotionalIntelligenceNotifications
    && !selfAssessmentStatus.isLoading
    && !selfAssessmentStatus.data;
  const needsPersonalityQuiz = canReceiveEmotionalIntelligenceNotifications
    && !personalityQuizStatus.isLoading
    && !personalityQuizStatus.data;
  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 canReadEsaFunding = canReceivePolicyNotifications && accessibleModuleIds.has('esa');
  const policyAcknowledgments = usePolicyAcknowledgments(canReceivePolicyNotifications && (
    canReadHandbook || canReadSafetyProtocols || canReadEsaFunding
  ));
  const handbookPolicies = usePolicies(canReadHandbook);
  const esaPolicyDocument = useEsaFundingPolicyDocument(canReadEsaFunding);
  const safetyProtocols = useSafetyProtocols(canReadSafetyProtocols);
  // 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'))
        || canReceiveSignOfWeekNotification
        || canManageWeeklySignSelection,
    },
  );
  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 normalizedSigns = useMemo(
    () => normalizeSignLanguageItems(signsQuery.payload),
    [signsQuery.payload],
  );
  const signOfWeek = useMemo(
    () => selectSignLanguageSignOfWeek(normalizedSigns, signOfWeekQuery.payload),
    [normalizedSigns, signOfWeekQuery.payload],
  );
  const needsSignOfWeek = canReceiveSignOfWeekNotification
    && !signOfWeekQuery.isLoading
    && !signsQuery.isLoading
    && !learnedSigns.isLoading
    && Boolean(signOfWeek)
    && !learnedSigns.learnedSignIds.has(signOfWeek?.id ?? '');
  const needsWeeklySignSelection = canManageWeeklySignSelection
    && !signOfWeekQuery.isLoading
    && !signsQuery.isLoading
    && (!signOfWeek || signOfWeekQuery.payload?.weekOf !== toWeekStartIso(new Date()));
  const needsWeeklyFrameContent = canManageWeeklyFrame
    && !frameContentQuery.isLoading
    && !frameContentQuery.error
    && (frameContentQuery.data?.length ?? 0) === 0;
  const needsDailyAttendanceContent = canManageDailyAttendance
    && !attendanceContentQuery.isLoading
    && !attendanceContentQuery.error
    && (attendanceContentQuery.data?.length ?? 0) === 0;
  const notifications = buildTopBarNotifications({
    needsZoneCheckIn,
    needsSafetyQuiz,
    needsSignOfWeek,
    needsWeeklySignSelection,
    needsWeeklyFrameContent,
    needsDailyAttendanceContent,
    needsEiSelfAssessment,
    needsPersonalityQuiz,
    communicationEvents: communicationEvents.data ?? [],
    acknowledgedCommunicationEventIds,
    handbookPolicies: [
      ...(handbookPolicies.data ?? []),
      ...(esaPolicyDocument.data
        ? [esaPolicyDocument.data]
        : []),
    ],
    safetyProtocols: safetyProtocols.data ?? [],
    policyAcknowledgments: policyAcknowledgments.data ?? [],
  });

  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,
    avatar: user?.avatar ?? null,
    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,
  };
}
