/**
 * Server-side Analytics for Next.js
 *
 * Track events from Server Components, API Routes, and Server Actions.
 */

import { headers } from 'next/headers';

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

interface ServerEvent {
  type: string;
  action: string;
  userId?: string;
  metadata?: Record<string, unknown>;
}

interface ServerAnalyticsConfig {
  collectorUrl: string;
  appName: string;
  enabled?: boolean;
}

// ─────────────────────────────────────────────────────────────────────────────
// Configuration
// ─────────────────────────────────────────────────────────────────────────────

let config: ServerAnalyticsConfig = {
  collectorUrl: process.env.ANALYTICS_COLLECTOR_URL || 'http://localhost:4001',
  appName: process.env.ANALYTICS_APP_NAME || 'nextjs-app',
  enabled: process.env.NODE_ENV !== 'test',
};

export function configureServerAnalytics(newConfig: Partial<ServerAnalyticsConfig>): void {
  config = { ...config, ...newConfig };
}

// ─────────────────────────────────────────────────────────────────────────────
// Server Session
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Generate a server-side session ID for request correlation.
 */
function generateServerSessionId(): string {
  return `srv_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
}

/**
 * Extract request context from Next.js headers.
 */
async function getRequestContext(): Promise<{
  sessionId: string;
  ip: string;
  userAgent: string;
  path: string;
}> {
  const headersList = await headers();

  return {
    sessionId: headersList.get('x-session-id') || generateServerSessionId(),
    ip:
      headersList.get('x-forwarded-for')?.split(',')[0]?.trim() ||
      headersList.get('x-real-ip') ||
      '0.0.0.0',
    userAgent: headersList.get('user-agent') || 'unknown',
    path: headersList.get('x-invoke-path') || '/',
  };
}

// ─────────────────────────────────────────────────────────────────────────────
// Tracking Functions
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Track an event from server-side code.
 *
 * @example
 * // In a Server Component
 * await trackServerEvent({
 *   type: 'page_view',
 *   action: 'product_viewed',
 *   metadata: { productId: '123' },
 * });
 */
export async function trackServerEvent(event: ServerEvent): Promise<void> {
  if (!config.enabled) return;

  const context = await getRequestContext();

  const payload = {
    sessionId: context.sessionId,
    userId: event.userId,
    type: event.type,
    action: event.action,
    timestamp: new Date().toISOString(),
    metadata: {
      ...event.metadata,
      _server: true,
      _ip: context.ip,
      _userAgent: context.userAgent,
      _path: context.path,
    },
    source: {
      app: config.appName,
      environment: process.env.NODE_ENV || 'development',
    },
  };

  try {
    await fetch(`${config.collectorUrl}/collect/engagement`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });
  } catch (error) {
    // Silent failure - don't break the app for analytics
    if (process.env.NODE_ENV === 'development') {
      console.warn('[Analytics] Server tracking failed:', error);
    }
  }
}

/**
 * Track a page view from a Server Component.
 *
 * @example
 * // In app/products/[id]/page.tsx
 * export default async function ProductPage({ params }) {
 *   await trackServerPageView({
 *     path: `/products/${params.id}`,
 *     metadata: { productId: params.id },
 *   });
 *   return <Product id={params.id} />;
 * }
 */
export async function trackServerPageView(options: {
  path: string;
  title?: string;
  userId?: string;
  metadata?: Record<string, unknown>;
}): Promise<void> {
  await trackServerEvent({
    type: 'navigation',
    action: 'page_view',
    userId: options.userId,
    metadata: {
      path: options.path,
      title: options.title,
      ...options.metadata,
    },
  });
}

/**
 * Track API route access.
 *
 * @example
 * // In app/api/users/route.ts
 * export async function GET(request: Request) {
 *   await trackApiCall({ route: '/api/users', method: 'GET' });
 *   return Response.json({ users: [] });
 * }
 */
export async function trackApiCall(options: {
  route: string;
  method: string;
  userId?: string;
  statusCode?: number;
  durationMs?: number;
  metadata?: Record<string, unknown>;
}): Promise<void> {
  await trackServerEvent({
    type: 'api_call',
    action: `${options.method} ${options.route}`,
    userId: options.userId,
    metadata: {
      route: options.route,
      method: options.method,
      statusCode: options.statusCode,
      durationMs: options.durationMs,
      ...options.metadata,
    },
  });
}

/**
 * Track Server Action execution.
 *
 * @example
 * // In a Server Action
 * 'use server';
 * export async function submitForm(data: FormData) {
 *   const start = Date.now();
 *   try {
 *     // ... action logic
 *     await trackServerAction({ action: 'submitForm', success: true, durationMs: Date.now() - start });
 *   } catch (error) {
 *     await trackServerAction({ action: 'submitForm', success: false, error: error.message });
 *     throw error;
 *   }
 * }
 */
export async function trackServerAction(options: {
  action: string;
  success: boolean;
  userId?: string;
  durationMs?: number;
  error?: string;
  metadata?: Record<string, unknown>;
}): Promise<void> {
  await trackServerEvent({
    type: 'server_action',
    action: options.action,
    userId: options.userId,
    metadata: {
      success: options.success,
      durationMs: options.durationMs,
      error: options.error,
      ...options.metadata,
    },
  });
}
