/**
 * A/B Testing — Audience targeting and filtering.
 * Platform, version, region, segment, and user property matching.
 */

import type { TargetingConfig } from './types.js';

export interface TargetingContext {
  platform?: string; // ios, android, web
  appVersion?: string; // semver
  osVersion?: string;
  deviceModel?: string;
  region?: string; // country code
  userSegments?: string[]; // pro, free, enterprise
  userProperties?: Record<string, string | number | boolean>;
}

/**
 * Check if a user matches the experiment's targeting criteria.
 */
export function matchesTargeting(
  context: TargetingContext,
  targeting: TargetingConfig
): boolean {
  // No targeting = everyone eligible
  if (!targeting || Object.keys(targeting).length === 0) {
    return true;
  }

  // Platform check
  if (targeting.platforms && targeting.platforms.length > 0) {
    if (!context.platform || !targeting.platforms.includes(context.platform)) {
      return false;
    }
  }

  // App version check (semver range)
  if (targeting.appVersions) {
    if (!context.appVersion) return false;
    if (!matchesVersionRange(context.appVersion, targeting.appVersions)) {
      return false;
    }
  }

  // Region check
  if (targeting.regions && targeting.regions.length > 0) {
    if (!context.region || !targeting.regions.includes(context.region)) {
      return false;
    }
  }

  // User segment check
  if (targeting.userSegments && targeting.userSegments.length > 0) {
    const userSegs = context.userSegments ?? [];
    const hasMatchingSegment = targeting.userSegments.some(seg => userSegs.includes(seg));
    if (!hasMatchingSegment) {
      return false;
    }
  }

  // User property check
  if (targeting.userProperties && Object.keys(targeting.userProperties).length > 0) {
    if (!context.userProperties) return false;
    for (const [key, value] of Object.entries(targeting.userProperties)) {
      if (context.userProperties[key] !== value) {
        return false;
      }
    }
  }

  return true;
}

/**
 * Check if version matches the min/max range.
 * Supports basic semver comparison.
 */
function matchesVersionRange(
  version: string,
  range: { min: string; max?: string }
): boolean {
  const v = parseSemver(version);
  const min = parseSemver(range.min);

  if (!v || !min) return true; // Be permissive on parse failure

  // Check min version
  if (compareSemver(v, min) < 0) return false;

  // Check max version if specified
  if (range.max) {
    const max = parseSemver(range.max);
    if (max && compareSemver(v, max) > 0) return false;
  }

  return true;
}

interface Semver {
  major: number;
  minor: number;
  patch: number;
}

function parseSemver(version: string): Semver | null {
  const match = version.match(/^(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
  if (!match) return null;

  return {
    major: parseInt(match[1], 10),
    minor: match[2] ? parseInt(match[2], 10) : 0,
    patch: match[3] ? parseInt(match[3], 10) : 0,
  };
}

function compareSemver(a: Semver, b: Semver): number {
  if (a.major !== b.major) return a.major - b.major;
  if (a.minor !== b.minor) return a.minor - b.minor;
  return a.patch - b.patch;
}

// ─────────────────────────────────────────────────────────────────────────────
// Exclusion Lists
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Check if user is in an exclusion list (beta users, internal accounts).
 */
export function isExcluded(
  userId: string,
  exclusionList: string[]
): boolean {
  return exclusionList.includes(userId);
}

/**
 * Common exclusion patterns.
 */
export const DEFAULT_EXCLUSIONS = {
  // Internal test accounts (patterns)
  internalPatterns: [
    /^test@/,
    /^admin@/,
    /@example\.com$/,
    /@test\.com$/,
  ],
  // Beta user segments to exclude from production experiments
  betaSegments: ['beta', 'alpha', 'internal', 'employee'],
};

/**
 * Check if user matches any exclusion pattern.
 */
export function matchesExclusion(
  userId: string,
  segments: string[] = []
): boolean {
  // Check patterns
  for (const pattern of DEFAULT_EXCLUSIONS.internalPatterns) {
    if (pattern.test(userId)) return true;
  }

  // Check segments
  for (const seg of segments) {
    if (DEFAULT_EXCLUSIONS.betaSegments.includes(seg)) return true;
  }

  return false;
}
