/**
 * Analytics Rollups module — unit tests.
 */

import { describe, it, expect } from 'vitest';
import {
  IngestMetricSchema,
  IngestBatchSchema,
  QueryRollupsSchema,
  AggregateRollupsSchema,
  SummaryQuerySchema,
  TopMetricsSchema,
} from './types.js';
import { toDailyKey, toWeeklyKey, toMonthlyKey, getDateKey } from './repository.js';

// ── Schema Validation ────────────────────────────────────────

describe('IngestMetricSchema', () => {
  it('accepts valid metric with defaults', () => {
    const result = IngestMetricSchema.parse({ metric: 'signups' });
    expect(result.metric).toBe('signups');
    expect(result.value).toBe(1);
    expect(result.timestamp).toBeUndefined();
  });

  it('accepts metric with dots and underscores', () => {
    const result = IngestMetricSchema.parse({ metric: 'user.session_start', value: 5 });
    expect(result.metric).toBe('user.session_start');
    expect(result.value).toBe(5);
  });

  it('rejects empty metric name', () => {
    expect(() => IngestMetricSchema.parse({ metric: '' })).toThrow();
  });

  it('rejects metric with invalid chars', () => {
    expect(() => IngestMetricSchema.parse({ metric: 'BAD-METRIC' })).toThrow();
  });

  it('accepts explicit timestamp', () => {
    const result = IngestMetricSchema.parse({
      metric: 'logins',
      timestamp: '2026-01-15T10:00:00.000Z',
    });
    expect(result.timestamp).toBe('2026-01-15T10:00:00.000Z');
  });
});

describe('IngestBatchSchema', () => {
  it('accepts batch of events', () => {
    const result = IngestBatchSchema.parse({
      events: [
        { metric: 'signups', value: 1 },
        { metric: 'logins', value: 3 },
      ],
    });
    expect(result.events).toHaveLength(2);
  });

  it('rejects empty batch', () => {
    expect(() => IngestBatchSchema.parse({ events: [] })).toThrow();
  });
});

describe('QueryRollupsSchema', () => {
  it('accepts defaults', () => {
    const result = QueryRollupsSchema.parse({});
    expect(result.period).toBe('daily');
  });

  it('accepts all params', () => {
    const result = QueryRollupsSchema.parse({
      period: 'weekly',
      from: '2026-01-01',
      to: '2026-01-31',
      metric: 'signups',
    });
    expect(result.period).toBe('weekly');
    expect(result.metric).toBe('signups');
  });

  it('rejects invalid period', () => {
    expect(() => QueryRollupsSchema.parse({ period: 'yearly' })).toThrow();
  });
});

// ── Date Key Helpers ─────────────────────────────────────────

describe('date key helpers', () => {
  it('toDailyKey returns YYYY-MM-DD', () => {
    expect(toDailyKey(new Date('2026-03-15T10:00:00Z'))).toBe('2026-03-15');
  });

  it('toMonthlyKey returns YYYY-MM', () => {
    expect(toMonthlyKey(new Date('2026-03-15T10:00:00Z'))).toBe('2026-03');
  });

  it('toWeeklyKey returns YYYY-Www format', () => {
    const key = toWeeklyKey(new Date('2026-03-15T10:00:00Z'));
    expect(key).toMatch(/^2026-W\d{2}$/);
  });

  it('getDateKey dispatches correctly', () => {
    const d = new Date('2026-06-01T12:00:00Z');
    expect(getDateKey(d, 'daily')).toBe('2026-06-01');
    expect(getDateKey(d, 'monthly')).toBe('2026-06');
    expect(getDateKey(d, 'weekly')).toMatch(/^2026-W\d{2}$/);
  });
});

// ── Aggregate Rollups Schema ────────────────────────────────

describe('AggregateRollupsSchema', () => {
  it('accepts weekly target', () => {
    const result = AggregateRollupsSchema.parse({ targetPeriod: 'weekly' });
    expect(result.targetPeriod).toBe('weekly');
    expect(result.sourceDate).toBeUndefined();
  });

  it('accepts monthly target with date', () => {
    const result = AggregateRollupsSchema.parse({
      targetPeriod: 'monthly',
      sourceDate: '2026-03-15',
    });
    expect(result.targetPeriod).toBe('monthly');
    expect(result.sourceDate).toBe('2026-03-15');
  });

  it('rejects daily as target', () => {
    expect(() => AggregateRollupsSchema.parse({ targetPeriod: 'daily' })).toThrow();
  });

  it('rejects missing targetPeriod', () => {
    expect(() => AggregateRollupsSchema.parse({})).toThrow();
  });
});

// ── Summary Query Schema ────────────────────────────────────

describe('SummaryQuerySchema', () => {
  it('defaults to 30 days', () => {
    const result = SummaryQuerySchema.parse({});
    expect(result.days).toBe(30);
  });

  it('accepts custom days', () => {
    const result = SummaryQuerySchema.parse({ days: '7' });
    expect(result.days).toBe(7);
  });

  it('rejects 0 days', () => {
    expect(() => SummaryQuerySchema.parse({ days: 0 })).toThrow();
  });

  it('rejects > 365 days', () => {
    expect(() => SummaryQuerySchema.parse({ days: 400 })).toThrow();
  });
});

// ── Top Metrics Schema ──────────────────────────────────────

describe('TopMetricsSchema', () => {
  it('accepts defaults', () => {
    const result = TopMetricsSchema.parse({});
    expect(result.period).toBe('daily');
    expect(result.limit).toBe(10);
    expect(result.date).toBeUndefined();
  });

  it('accepts all params', () => {
    const result = TopMetricsSchema.parse({
      period: 'weekly',
      date: '2026-W12',
      limit: '5',
    });
    expect(result.period).toBe('weekly');
    expect(result.date).toBe('2026-W12');
    expect(result.limit).toBe(5);
  });

  it('rejects limit > 50', () => {
    expect(() => TopMetricsSchema.parse({ limit: 100 })).toThrow();
  });
});
