/**
 * Tests for extraction usage quota enforcement — plan tiers + in-memory tracker.
 */

import { describe, it, expect } from 'vitest';
import {
  getQuota,
  checkQuota,
  incrementUsage,
  getUsageSummary,
  ExtractionUsageSchema,
} from './usage.js';

describe('getQuota', () => {
  it('returns 10 for free plan', () => {
    expect(getQuota('free')).toBe(10);
  });

  it('returns 100 for pro plan', () => {
    expect(getQuota('pro')).toBe(100);
  });

  it('returns Infinity for enterprise plan', () => {
    expect(getQuota('enterprise')).toBe(Infinity);
  });

  it('falls back to free tier for unknown plans', () => {
    expect(getQuota('unknown')).toBe(10);
    expect(getQuota('')).toBe(10);
  });
});

describe('checkQuota', () => {
  it('allows first request for free user', () => {
    const result = checkQuota('fresh-user-1', 'free');
    expect(result.allowed).toBe(true);
    expect(result.limit).toBe(10);
    expect(result.used).toBe(0);
    expect(result.remaining).toBe(10);
  });

  it('enterprise users always allowed with Infinity remaining', () => {
    const result = checkQuota('enterprise-user', 'enterprise');
    expect(result.allowed).toBe(true);
    expect(result.remaining).toBe(Infinity);
    expect(result.limit).toBe(Infinity);
  });

  it('defaults to free plan when no plan specified', () => {
    const result = checkQuota('no-plan-user');
    expect(result.limit).toBe(10);
  });

  it('tracks usage after increments', () => {
    const userId = 'tracked-user-' + Date.now();
    incrementUsage(userId, 'free');
    incrementUsage(userId, 'free');
    incrementUsage(userId, 'free');

    const result = checkQuota(userId, 'free');
    expect(result.used).toBe(3);
    expect(result.remaining).toBe(7);
    expect(result.allowed).toBe(true);
  });

  it('blocks when quota exceeded', () => {
    const userId = 'blocked-user-' + Date.now();
    for (let i = 0; i < 10; i++) {
      incrementUsage(userId, 'free');
    }

    const result = checkQuota(userId, 'free');
    expect(result.allowed).toBe(false);
    expect(result.remaining).toBe(0);
    expect(result.used).toBe(10);
  });

  it('pro users have higher quota', () => {
    const userId = 'pro-user-' + Date.now();
    for (let i = 0; i < 10; i++) {
      incrementUsage(userId, 'pro');
    }

    const result = checkQuota(userId, 'pro');
    expect(result.allowed).toBe(true);
    expect(result.remaining).toBe(90);
  });
});

describe('incrementUsage', () => {
  it('increments usage counter', () => {
    const userId = 'inc-user-' + Date.now();
    incrementUsage(userId);

    const q1 = checkQuota(userId, 'free');
    expect(q1.used).toBe(1);

    incrementUsage(userId);
    const q2 = checkQuota(userId, 'free');
    expect(q2.used).toBe(2);
  });

  it('tracks different users separately', () => {
    const userA = 'user-a-' + Date.now();
    const userB = 'user-b-' + Date.now();

    incrementUsage(userA);
    incrementUsage(userA);
    incrementUsage(userB);

    expect(checkQuota(userA, 'free').used).toBe(2);
    expect(checkQuota(userB, 'free').used).toBe(1);
  });
});

describe('getUsageSummary', () => {
  it('returns complete summary for new user', () => {
    const userId = 'summary-user-' + Date.now();
    const summary = getUsageSummary(userId, 'pro');

    expect(summary.userId).toBe(userId);
    expect(summary.date).toMatch(/^\d{4}-\d{2}-\d{2}$/);
    expect(summary.used).toBe(0);
    expect(summary.limit).toBe(100);
    expect(summary.remaining).toBe(100);
    expect(summary.plan).toBe('pro');
  });

  it('returns -1 for limit/remaining when enterprise (Infinity)', () => {
    const userId = 'ent-summary-' + Date.now();
    const summary = getUsageSummary(userId, 'enterprise');

    expect(summary.limit).toBe(-1);
    expect(summary.remaining).toBe(-1);
    expect(summary.plan).toBe('enterprise');
  });

  it('reflects current usage', () => {
    const userId = 'used-summary-' + Date.now();
    incrementUsage(userId, 'free');
    incrementUsage(userId, 'free');

    const summary = getUsageSummary(userId, 'free');
    expect(summary.used).toBe(2);
    expect(summary.remaining).toBe(8);
  });

  it('defaults to free plan', () => {
    const userId = 'default-plan-' + Date.now();
    const summary = getUsageSummary(userId);
    expect(summary.plan).toBe('free');
    expect(summary.limit).toBe(10);
  });
});

describe('ExtractionUsageSchema', () => {
  it('accepts valid usage document', () => {
    const result = ExtractionUsageSchema.safeParse({
      id: 'usage-1',
      userId: 'user-1',
      productId: 'lysnrai',
      date: '2026-02-16',
      count: 5,
      plan: 'free',
      updatedAt: '2026-02-16T10:00:00.000Z',
    });
    expect(result.success).toBe(true);
  });

  it('rejects negative count', () => {
    const result = ExtractionUsageSchema.safeParse({
      id: 'usage-1',
      userId: 'user-1',
      productId: 'lysnrai',
      date: '2026-02-16',
      count: -1,
      plan: 'free',
      updatedAt: '2026-02-16T10:00:00.000Z',
    });
    expect(result.success).toBe(false);
  });

  it('rejects non-integer count', () => {
    const result = ExtractionUsageSchema.safeParse({
      id: 'usage-1',
      userId: 'user-1',
      productId: 'lysnrai',
      date: '2026-02-16',
      count: 5.5,
      plan: 'free',
      updatedAt: '2026-02-16T10:00:00.000Z',
    });
    expect(result.success).toBe(false);
  });

  it('rejects missing fields', () => {
    const result = ExtractionUsageSchema.safeParse({ id: 'usage-1' });
    expect(result.success).toBe(false);
  });
});
