/**
 * Broadcast module tests — schema validation and targeting engine.
 */

import { describe, it, expect } from 'vitest';
import { CreateBroadcastSchema, UpdateBroadcastSchema, InAppMessageActionSchema } from './types.js';
import { evaluateTarget, buildTargetQuery, extractTargetingContext } from './targeting.js';
import type { BroadcastTarget, TargetingContext } from './types.js';

// ── Schema validation ──

describe('CreateBroadcastSchema', () => {
  it('validates minimal broadcast', () => {
    const result = CreateBroadcastSchema.safeParse({
      title: 'Welcome!',
      body: 'Welcome to the app',
      target: {},
      channels: ['in_app'],
    });
    expect(result.success).toBe(true);
  });

  it('rejects empty channels', () => {
    const result = CreateBroadcastSchema.safeParse({
      title: 'Welcome!',
      body: 'Hello',
      target: {},
      channels: [],
    });
    expect(result.success).toBe(false);
  });

  it('validates full broadcast with targeting + media', () => {
    const result = CreateBroadcastSchema.safeParse({
      title: 'Big Update!',
      body: 'Check out the new features',
      bodyMarkdown: '# Big Update\n\nCheck out the new features',
      ctaText: 'Learn More',
      ctaUrl: 'https://example.com/update',
      imageUrl: 'https://example.com/img.png',
      media: [{ type: 'image', url: 'https://example.com/hero.jpg', width: 800, height: 600 }],
      target: {
        userSegments: ['pro'],
        platforms: ['ios', 'android'],
        percentageRollout: 50,
      },
      channels: ['push', 'in_app'],
      scheduledAt: '2026-04-01T10:00:00.000Z',
    });
    expect(result.success).toBe(true);
  });
});

describe('UpdateBroadcastSchema', () => {
  it('allows partial updates', () => {
    const result = UpdateBroadcastSchema.safeParse({ title: 'New Title' });
    expect(result.success).toBe(true);
  });

  it('allows status change', () => {
    const result = UpdateBroadcastSchema.safeParse({ status: 'paused' });
    expect(result.success).toBe(true);
  });
});

describe('InAppMessageActionSchema', () => {
  it('validates read action', () => {
    expect(InAppMessageActionSchema.safeParse({ action: 'read' }).success).toBe(true);
  });

  it('rejects invalid action', () => {
    expect(InAppMessageActionSchema.safeParse({ action: 'delete' }).success).toBe(false);
  });
});

// ── Targeting engine ──

describe('evaluateTarget', () => {
  const baseContext: TargetingContext = {
    userId: 'user-1',
    productId: 'testprod',
    platform: 'ios',
    appVersion: '2.1.0',
    osVersion: '17.0',
    countryCode: 'US',
    regionCode: 'US-CA',
    userSegments: ['pro'],
  };

  it('matches with empty target (all users)', () => {
    expect(evaluateTarget({}, baseContext)).toBe(true);
  });

  it('matches user segment', () => {
    const target: BroadcastTarget = { userSegments: ['pro', 'enterprise'] };
    expect(evaluateTarget(target, baseContext)).toBe(true);
  });

  it('rejects non-matching segment', () => {
    const target: BroadcastTarget = { userSegments: ['churned'] };
    expect(evaluateTarget(target, baseContext)).toBe(false);
  });

  it('matches platform', () => {
    const target: BroadcastTarget = { platforms: ['ios', 'android'] };
    expect(evaluateTarget(target, baseContext)).toBe(true);
  });

  it('rejects non-matching platform', () => {
    const target: BroadcastTarget = { platforms: ['android'] };
    expect(evaluateTarget(target, baseContext)).toBe(false);
  });

  it('matches app version range', () => {
    const target: BroadcastTarget = { appVersionMin: '2.0.0', appVersionMax: '3.0.0' };
    expect(evaluateTarget(target, baseContext)).toBe(true);
  });

  it('rejects below min version', () => {
    const target: BroadcastTarget = { appVersionMin: '3.0.0' };
    expect(evaluateTarget(target, baseContext)).toBe(false);
  });

  it('matches country code', () => {
    const target: BroadcastTarget = { countryCodes: ['US', 'CA'] };
    expect(evaluateTarget(target, baseContext)).toBe(true);
  });

  it('rejects non-matching country', () => {
    const target: BroadcastTarget = { countryCodes: ['DE'] };
    expect(evaluateTarget(target, baseContext)).toBe(false);
  });

  it('matches specific user ID', () => {
    const target: BroadcastTarget = { specificUserIds: ['user-1', 'user-2'] };
    expect(evaluateTarget(target, baseContext)).toBe(true);
  });

  it('rejects non-matching user ID', () => {
    const target: BroadcastTarget = { specificUserIds: ['user-99'] };
    expect(evaluateTarget(target, baseContext)).toBe(false);
  });

  it('percentage rollout is deterministic', () => {
    const target: BroadcastTarget = { percentageRollout: 50 };
    const result1 = evaluateTarget(target, baseContext);
    const result2 = evaluateTarget(target, baseContext);
    expect(result1).toBe(result2); // Same user → same result
  });
});

// ── Target query builder ──

describe('buildTargetQuery', () => {
  it('returns empty for empty target', () => {
    const { whereClauses, parameters } = buildTargetQuery({});
    expect(whereClauses).toHaveLength(0);
    expect(parameters).toHaveLength(0);
  });

  it('builds platform filter', () => {
    const { whereClauses, parameters } = buildTargetQuery({ platforms: ['ios', 'android'] });
    expect(whereClauses).toContain('(c.platform IN @platforms)');
    expect(parameters.find(p => p.name === '@platforms')?.value).toEqual(['ios', 'android']);
  });
});

// ── Context extraction ──

describe('extractTargetingContext', () => {
  it('extracts from headers and JWT', () => {
    const ctx = extractTargetingContext(
      {
        'x-product-id': 'myapp',
        'x-platform': 'ios',
        'x-app-version': '2.0.0',
        'x-os-version': '17.0',
        'x-country-code': 'US',
      },
      { sub: 'user-1', segments: ['pro'] }
    );
    expect(ctx.userId).toBe('user-1');
    expect(ctx.platform).toBe('ios');
    expect(ctx.countryCode).toBe('US');
    expect(ctx.userSegments).toEqual(['pro']);
  });

  it('falls back to defaults', () => {
    const ctx = extractTargetingContext({}, undefined);
    expect(ctx.userId).toBe('anonymous');
    expect(ctx.platform).toBe('web');
    expect(ctx.appVersion).toBe('0.0.0');
  });
});
