/**
 * Funnel Tracking Utilities
 *
 * Generic funnel tracking that works with any multi-step flow.
 * All state is held in memory (consent-free).
 */

// ─────────────────────────────────────────────────────────────────────────────
// Types
// ─────────────────────────────────────────────────────────────────────────────

export interface FunnelStep {
  name: string;
  timestamp: number;
  metadata?: Record<string, unknown>;
}

export interface FunnelState {
  funnelId: string;
  sessionId: string;
  entryReferrer: string;
  entryTimestamp: number;
  steps: FunnelStep[];
  metadata?: Record<string, unknown>;
}

export interface FunnelEventPayload {
  funnelId: string;
  sessionId: string;
  step: string;
  stepIndex: number;
  timeFromEntryMs: number;
  timeFromPreviousStepMs: number | null;
  entryReferrer: string;
  metadata?: Record<string, unknown>;
}

// ─────────────────────────────────────────────────────────────────────────────
// In-Memory State (Consent-Free)
// ─────────────────────────────────────────────────────────────────────────────

// Module-level state - resets on tab close
let currentSessionId: string | null = null;
const activeFunnels = new Map<string, FunnelState>();

/**
 * Get or create a session ID for the current SPA lifecycle.
 */
function getSessionId(): string {
  if (!currentSessionId) {
    currentSessionId = `${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
  }
  return currentSessionId;
}

// ─────────────────────────────────────────────────────────────────────────────
// Funnel Operations
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Start a new funnel.
 *
 * Call this when the user enters the first step of a conversion flow.
 *
 * @example
 * ```ts
 * // User lands on signup page
 * startFunnel('signup', { plan: 'pro' });
 * ```
 */
export function startFunnel(
  funnelId: string,
  metadata?: Record<string, unknown>,
): FunnelState {
  const sessionId = getSessionId();
  const now = Date.now();

  const state: FunnelState = {
    funnelId,
    sessionId,
    entryReferrer: typeof document !== 'undefined' ? document.referrer || 'direct' : 'unknown',
    entryTimestamp: now,
    steps: [],
    metadata,
  };

  activeFunnels.set(funnelId, state);

  return state;
}

/**
 * Track a funnel step completion.
 *
 * @example
 * ```ts
 * // User completes email verification step
 * trackFunnelStep('signup', 'email_verified', { method: 'magic_link' });
 * ```
 */
export function trackFunnelStep(
  funnelId: string,
  stepName: string,
  metadata?: Record<string, unknown>,
): FunnelEventPayload | null {
  const state = activeFunnels.get(funnelId);

  if (!state) {
    console.warn(`[Funnel] No active funnel found: ${funnelId}. Call startFunnel first.`);
    return null;
  }

  const now = Date.now();
  const previousStep = state.steps[state.steps.length - 1];

  // Add step to state
  state.steps.push({
    name: stepName,
    timestamp: now,
    metadata,
  });

  // Build event payload
  const payload: FunnelEventPayload = {
    funnelId,
    sessionId: state.sessionId,
    step: stepName,
    stepIndex: state.steps.length,
    timeFromEntryMs: now - state.entryTimestamp,
    timeFromPreviousStepMs: previousStep ? now - previousStep.timestamp : null,
    entryReferrer: state.entryReferrer,
    metadata: {
      ...state.metadata,
      ...metadata,
    },
  };

  // Send to analytics backend
  sendFunnelEvent(payload);

  return payload;
}

/**
 * Mark funnel as completed (conversion).
 *
 * @example
 * ```ts
 * // User successfully signed up
 * completeFunnel('signup', { userId: 'usr_123' });
 * ```
 */
export function completeFunnel(
  funnelId: string,
  metadata?: Record<string, unknown>,
): FunnelEventPayload | null {
  const payload = trackFunnelStep(funnelId, 'completed', metadata);

  // Clean up funnel state after completion
  activeFunnels.delete(funnelId);

  return payload;
}

/**
 * Abandon a funnel (user explicitly exits).
 *
 * @example
 * ```ts
 * // User clicks "Cancel" on signup
 * abandonFunnel('signup', { reason: 'user_cancelled' });
 * ```
 */
export function abandonFunnel(
  funnelId: string,
  metadata?: Record<string, unknown>,
): FunnelEventPayload | null {
  const payload = trackFunnelStep(funnelId, 'abandoned', metadata);

  activeFunnels.delete(funnelId);

  return payload;
}

/**
 * Get current funnel state.
 */
export function getFunnelState(funnelId: string): FunnelState | null {
  return activeFunnels.get(funnelId) || null;
}

/**
 * Check if a funnel is active.
 */
export function isFunnelActive(funnelId: string): boolean {
  return activeFunnels.has(funnelId);
}

// ─────────────────────────────────────────────────────────────────────────────
// API Communication
// ─────────────────────────────────────────────────────────────────────────────

const ANALYTICS_ENDPOINT = '/api/track/funnel';

async function sendFunnelEvent(payload: FunnelEventPayload): Promise<void> {
  try {
    await fetch(ANALYTICS_ENDPOINT, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
      keepalive: true, // Survive page unload
    });
  } catch {
    // Fail silently - analytics shouldn't break user experience
    console.debug('[Funnel] Failed to send event:', payload.step);
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Cleanup on Page Unload
// ─────────────────────────────────────────────────────────────────────────────

if (typeof window !== 'undefined') {
  window.addEventListener('beforeunload', () => {
    // Track abandonment for all active funnels on page unload
    for (const [funnelId] of activeFunnels) {
      abandonFunnel(funnelId, { reason: 'page_unload' });
    }
  });
}
