/**
 * Performance-optimized invitation hooks.
 * Uses useSyncExternalStore for fine-grained reactivity.
 */

import { useSyncExternalStore, useMemo, useCallback } from 'react';
import type { Invitation } from '../../services/invitation.js';
import type { XOInvitation } from '@xo-cash/types';
import { useAppContext } from './useAppContext.js';

/**
 * Get all invitations reactively.
 * Re-renders when invitations are added or removed.
 */
export function useInvitations(): Invitation[] {
  const { appService } = useAppContext();

  const subscribe = useCallback(
    (callback: () => void) => {
      if (!appService) {
        return () => {};
      }

      // Subscribe to invitation list changes
      const onAdded = () => callback();
      const onRemoved = () => callback();

      appService.on('invitation-added', onAdded);
      appService.on('invitation-removed', onRemoved);

      return () => {
        appService.off('invitation-added', onAdded);
        appService.off('invitation-removed', onRemoved);
      };
    },
    [appService]
  );

  const getSnapshot = useCallback(() => {
    return appService?.invitations ?? [];
  }, [appService]);

  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
}

/**
 * Get a single invitation by ID with selective re-rendering.
 * Only re-renders when the specific invitation is updated.
 */
export function useInvitation(invitationId: string | null): Invitation | null {
  const { appService } = useAppContext();

  const subscribe = useCallback(
    (callback: () => void) => {
      if (!appService || !invitationId) {
        return () => {};
      }

      // Find the invitation instance
      const invitation = appService.invitations.find(
        (inv) => inv.data.invitationIdentifier === invitationId
      );

      if (!invitation) {
        return () => {};
      }

      // Subscribe to this specific invitation's updates
      const onUpdated = () => callback();
      const onStatusChanged = () => callback();

      invitation.on('invitation-updated', onUpdated);
      invitation.on('invitation-status-changed', onStatusChanged);

      // Also subscribe to list changes in case the invitation is removed
      const onRemoved = () => callback();
      appService.on('invitation-removed', onRemoved);

      return () => {
        invitation.off('invitation-updated', onUpdated);
        invitation.off('invitation-status-changed', onStatusChanged);
        appService.off('invitation-removed', onRemoved);
      };
    },
    [appService, invitationId]
  );

  const getSnapshot = useCallback(() => {
    if (!appService || !invitationId) {
      return null;
    }

    return (
      appService.invitations.find(
        (inv) => inv.data.invitationIdentifier === invitationId
      ) ?? null
    );
  }, [appService, invitationId]);

  return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
}

/**
 * Get invitation data with memoization.
 * Returns stable references to prevent unnecessary re-renders.
 */
export function useInvitationData(invitationId: string | null): XOInvitation | null {
  const invitation = useInvitation(invitationId);

  return useMemo(() => {
    return invitation?.data ?? null;
  }, [invitation?.data.invitationIdentifier, invitation?.data.commits?.length]);
}

/**
 * Hook to create invitations.
 * Returns a memoized function to create invitations.
 */
export function useCreateInvitation() {
  const { appService } = useAppContext();

  return useCallback(
    async (invitation: XOInvitation | string): Promise<Invitation> => {
      if (!appService) {
        throw new Error('AppService not initialized');
      }

      return await appService.createInvitation(invitation);
    },
    [appService]
  );
}

/**
 * Hook to get all invitations with their IDs.
 * Useful for lists where you only need IDs (prevents re-renders on data changes).
 */
export function useInvitationIds(): string[] {
  const invitations = useInvitations();

  return useMemo(() => {
    return invitations.map((inv) => inv.data.invitationIdentifier);
  }, [invitations]);
}
