import { createNavigationContainerRef } from '@react-navigation/native';
import type { Notification } from 'expo-notifications';
import { logError } from '@/lib/errors';

// Shared ref so non-component code (notification handlers, deep links) can
// drive navigation without prop-drilling. Typed via the global
// ReactNavigation.RootParamList augmentation in navigation/types.ts.
export const navigationRef = createNavigationContainerRef();

// Shape the worker (go/internal/human/pushnotify/notifier.go::buildMessages)
// puts in `Notifications.notification.request.content.data`.
type ParticleCreatedData = {
  kind: 'particle_created';
  network_id: string;
  stream_id: string;
  particle_id: string;
  sender_human_id: string;
  particle_kind: string;
};

function isParticleCreatedData(data: unknown): data is ParticleCreatedData {
  return (
    typeof data === 'object' &&
    data !== null &&
    (data as { kind?: unknown }).kind === 'particle_created' &&
    typeof (data as { network_id?: unknown }).network_id === 'string' &&
    typeof (data as { stream_id?: unknown }).stream_id === 'string'
  );
}

// If a tap arrives before the navigator has mounted (cold start), stash it and
// replay as soon as the container reports ready.
let pendingNavigation: ParticleCreatedData | null = null;

/**
 * Routes a single notification tap to the appropriate screen. Safe to call
 * before the navigation container is ready — it queues the route and replays
 * it once `navigationRef.isReady()` flips true.
 */
export function routeNotificationTap(notification: Notification): void {
  try {
    const data = notification.request.content.data;
    if (!isParticleCreatedData(data)) return;

    if (!navigationRef.isReady()) {
      pendingNavigation = data;
      return;
    }
    navigateToStream(data);
  } catch (err) {
    logError(err, { scope: 'push.route' });
  }
}

/**
 * Called once by App.tsx when the NavigationContainer mounts. Drains any
 * cold-start tap that arrived before navigation was ready.
 */
export function flushPendingNavigation(): void {
  if (!pendingNavigation) return;
  const data = pendingNavigation;
  pendingNavigation = null;
  if (navigationRef.isReady()) {
    navigateToStream(data);
  }
}

function navigateToStream(data: ParticleCreatedData): void {
  navigationRef.navigate('StreamView', {
    networkId: data.network_id,
    streamId: data.stream_id,
  });
}
