import { describe, it, expect, vi, beforeEach } from 'vitest';
import { Analytics, EventSchema, EventName } from '../../src/analytics';
import { PostHog } from 'posthog-node';

vi.mock('posthog-node');

describe('Analytics SDK (PostHog Cloud — v2 Post-Review)', () => {
  let analytics: Analytics;
  let mockPostHog: vi.Mocked<PostHog>;

  beforeEach(() => {
    vi.clearAllMocks();
    mockPostHog = new PostHog('phc_test_key', { host: 'https://us.i.posthog.com' }) as any;
    analytics = new Analytics(mockPostHog);
  });

  // ── Schema Validation (Zod) ──────────────────────────────

  describe('Event Taxonomy Validation', () => {
    it('accepts valid account.signup.completed event', () => {
      const event = {
        name: EventName.SignupCompleted,
        tenant_id: 'tenant-123',
        product: 'route' as const,
        properties: { method: 'github_sso' },
      };
      expect(() => EventSchema.parse(event)).not.toThrow();
    });

    it('rejects events missing tenant_id', () => {
      const event = {
        name: EventName.SignupCompleted,
        product: 'route',
        properties: { method: 'email' },
      };
      expect(() => EventSchema.parse(event as any)).toThrow(/tenant_id/);
    });

    it('accepts valid activation event', () => {
      const event = {
        name: EventName.FirstDollarSaved,
        tenant_id: 'tenant-123',
        product: 'route' as const,
        properties: { savings_amount: 1.50 },
      };
      expect(() => EventSchema.parse(event)).not.toThrow();
    });

    it('accepts valid upgrade event', () => {
      const event = {
        name: EventName.UpgradeCompleted,
        tenant_id: 'tenant-123',
        product: 'route' as const,
        properties: { plan: 'pro', mrr_increase: 49 },
      };
      expect(() => EventSchema.parse(event)).not.toThrow();
    });
  });

  // ── track() Behavior ─────────────────────────────────────

  describe('track()', () => {
    it('captures valid events via PostHog client', () => {
      const result = analytics.track({
        name: EventName.SignupCompleted,
        tenant_id: 'tenant-123',
        product: 'route',
        properties: { method: 'email' },
      });

      expect(result).toBe(true);
      expect(mockPostHog.capture).toHaveBeenCalledWith(
        expect.objectContaining({
          distinctId: 'tenant-123',
          event: 'account.signup.completed',
          properties: expect.objectContaining({
            product: 'route',
            method: 'email',
          }),
        })
      );
    });

    it('does NOT include $set in track calls (use identify instead)', () => {
      analytics.track({
        name: EventName.SignupCompleted,
        tenant_id: 'tenant-123',
        product: 'route',
        properties: { method: 'github_sso' },
      });

      const captureCall = mockPostHog.capture.mock.calls[0][0];
      expect(captureCall.properties).not.toHaveProperty('$set');
    });

    it('does NOT pass timestamp (let PostHog handle it to avoid clock skew)', () => {
      analytics.track({
        name: EventName.SignupCompleted,
        tenant_id: 'tenant-123',
        product: 'route',
        properties: { method: 'email' },
      });

      const captureCall = mockPostHog.capture.mock.calls[0][0];
      expect(captureCall).not.toHaveProperty('timestamp');
    });

    it('returns false and does NOT call PostHog if base validation fails', () => {
      const result = analytics.track({
        name: 'invalid.event' as any,
        tenant_id: 'tenant-123',
        product: 'route',
      });

      expect(result).toBe(false);
      expect(mockPostHog.capture).not.toHaveBeenCalled();
    });

    it('returns false if per-event property validation fails (strict schema)', () => {
      const result = analytics.track({
        name: EventName.SignupCompleted,
        tenant_id: 'tenant-123',
        product: 'route',
        properties: { method: 'invalid_method' }, // Not in enum
      });

      expect(result).toBe(false);
      expect(mockPostHog.capture).not.toHaveBeenCalled();
    });

    it('rejects unknown properties (strict mode — no PII loophole)', () => {
      const result = analytics.track({
        name: EventName.SignupCompleted,
        tenant_id: 'tenant-123',
        product: 'route',
        properties: { method: 'email', email: 'user@example.com' }, // PII leak attempt
      });

      expect(result).toBe(false);
      expect(mockPostHog.capture).not.toHaveBeenCalled();
    });

    it('does NOT flush after each track call (Lambda batching)', () => {
      analytics.track({
        name: EventName.SignupCompleted,
        tenant_id: 'tenant-123',
        product: 'route',
        properties: { method: 'email' },
      });

      expect(mockPostHog.flushAsync).not.toHaveBeenCalled();
    });
  });

  // ── identify() ───────────────────────────────────────────

  describe('identify()', () => {
    it('calls PostHog identify with tenant_id as distinctId', () => {
      analytics.identify('tenant-123', { company: 'Acme' });

      expect(mockPostHog.identify).toHaveBeenCalledWith(
        expect.objectContaining({
          distinctId: 'tenant-123',
          properties: expect.objectContaining({
            tenant_id: 'tenant-123',
            company: 'Acme',
          }),
        })
      );
    });
  });

  // ── flush() ──────────────────────────────────────────────

  describe('flush()', () => {
    it('calls flushAsync on the PostHog client', async () => {
      await analytics.flush();
      expect(mockPostHog.flushAsync).toHaveBeenCalledTimes(1);
    });
  });

  // ── NoOp Client ──────────────────────────────────────────

  describe('NoOp Client (missing API key)', () => {
    it('does not throw when tracking without API key', () => {
      const noopAnalytics = new Analytics(); // No client, no env var
      const result = noopAnalytics.track({
        name: EventName.SignupCompleted,
        tenant_id: 'tenant-123',
        product: 'route',
        properties: { method: 'email' },
      });
      expect(result).toBe(true); // NoOp accepts everything silently
    });
  });

  // ── Session Replay ───────────────────────────────────────

  describe('Security', () => {
    it('session replay is disabled', () => {
      expect(analytics.isSessionReplayEnabled).toBe(false);
    });
  });
});
