/**
 * Onboarding repository — cloud-agnostic via @bytelyst/datastore.
 */

import type { FilterMap } from '@bytelyst/datastore';
import { getCollection } from '../../lib/datastore.js';
import type {
  OnboardingEventDoc,
  OnboardingCompletionDoc,
  OnboardingFunnel,
  FunnelStep,
} from './types.js';

function stepCollection() {
  return getCollection<OnboardingEventDoc>('onboarding_events', '/productId');
}

function completionCollection() {
  return getCollection<OnboardingCompletionDoc>('onboarding_completions', '/productId');
}

// ── Step tracking ──

export async function trackStep(doc: OnboardingEventDoc): Promise<OnboardingEventDoc> {
  return stepCollection().upsert(doc);
}

export async function trackCompletion(
  doc: OnboardingCompletionDoc
): Promise<OnboardingCompletionDoc> {
  return completionCollection().upsert(doc);
}

// ── Funnel query ──

export async function getFunnel(
  productId: string,
  from?: string,
  to?: string
): Promise<OnboardingFunnel> {
  const stepFilter: FilterMap = { productId };
  if (from) stepFilter.completedAt = { ...((stepFilter.completedAt as object) ?? {}), $gte: from };
  if (to) stepFilter.completedAt = { ...((stepFilter.completedAt as object) ?? {}), $lte: to };

  const steps = await stepCollection().findMany({ filter: stepFilter });

  const completionFilter: FilterMap = { productId };
  if (from)
    completionFilter.completedAt = {
      ...((completionFilter.completedAt as object) ?? {}),
      $gte: from,
    };
  if (to)
    completionFilter.completedAt = {
      ...((completionFilter.completedAt as object) ?? {}),
      $lte: to,
    };

  const completions = await completionCollection().findMany({ filter: completionFilter });

  // Aggregate steps by stepName+stepIndex
  const stepMap = new Map<string, { stepName: string; stepIndex: number; userIds: Set<string> }>();
  const allUserIds = new Set<string>();

  for (const s of steps) {
    allUserIds.add(s.userId);
    const key = `${s.stepIndex}:${s.stepName}`;
    const existing = stepMap.get(key);
    if (existing) {
      existing.userIds.add(s.userId);
    } else {
      stepMap.set(key, {
        stepName: s.stepName,
        stepIndex: s.stepIndex,
        userIds: new Set([s.userId]),
      });
    }
  }

  const totalStarted = allUserIds.size;
  const totalCompleted = new Set(completions.map(c => c.userId)).size;

  // Build funnel steps sorted by stepIndex
  const funnelSteps: FunnelStep[] = Array.from(stepMap.values())
    .sort((a, b) => a.stepIndex - b.stepIndex)
    .map(s => ({
      stepName: s.stepName,
      stepIndex: s.stepIndex,
      uniqueUsers: s.userIds.size,
      conversionRate: totalStarted > 0 ? s.userIds.size / totalStarted : 0,
    }));

  // Average duration from completions
  const durations = completions.filter(c => c.durationMs != null).map(c => c.durationMs!);
  const avgDurationMs =
    durations.length > 0
      ? Math.round(durations.reduce((a, b) => a + b, 0) / durations.length)
      : undefined;

  return {
    productId,
    totalStarted,
    totalCompleted,
    completionRate: totalStarted > 0 ? totalCompleted / totalStarted : 0,
    steps: funnelSteps,
    avgDurationMs,
  };
}

// ── User progress query ──

export async function getUserSteps(
  productId: string,
  userId: string
): Promise<OnboardingEventDoc[]> {
  return stepCollection().findMany({
    filter: { productId, userId },
    sort: { stepIndex: 1 },
  });
}

export async function getUserCompletion(
  productId: string,
  userId: string
): Promise<OnboardingCompletionDoc | null> {
  const results = await completionCollection().findMany({
    filter: { productId, userId },
    limit: 1,
  });
  return results[0] ?? null;
}
