/**
 * Route-level tests for usage module — Fastify inject.
 */

import Fastify from 'fastify';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

const repoMock = {
  list: vi.fn(),
  upsert: vi.fn(),
  getMonthlyUsage: vi.fn(),
  getByDate: vi.fn(),
};

vi.mock('./repository.js', () => repoMock);

vi.mock('../../lib/request-context.js', () => ({
  getRequestProductId: () => 'lysnrai',
}));

const baseUsage = {
  id: 'usg_2026-02-16_user_1',
  productId: 'lysnrai',
  userId: 'user_1',
  date: '2026-02-16',
  dictations: 5,
  words: 250,
  durationMs: 30000,
  tokensUsed: 1200,
  costUsd: 0.01,
  model: 'gpt-4o-mini',
  source: 'desktop',
  createdAt: '2026-02-16T00:00:00Z',
};

describe('usageRoutes', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('GET /usage returns usage records', async () => {
    repoMock.list.mockResolvedValue([baseUsage]);
    const { usageRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(usageRoutes, { prefix: '/api' });

    const res = await app.inject({ method: 'GET', url: '/api/usage' });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.records).toHaveLength(1);
    expect(data.count).toBe(1);
  });

  it('GET /usage/summary returns aggregated summary', async () => {
    repoMock.list.mockResolvedValue([baseUsage]);
    const { usageRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(usageRoutes, { prefix: '/api' });

    const res = await app.inject({ method: 'GET', url: '/api/usage/summary' });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.totalWords).toBe(250);
    expect(data.totalDictations).toBe(5);
    expect(data.totalTokens).toBe(1200);
    expect(data.modelBreakdown).toHaveLength(1);
    expect(data.sourceBreakdown).toHaveLength(1);
    expect(data.productBreakdown).toHaveLength(1);
  });

  it('POST /usage upserts a usage record', async () => {
    repoMock.upsert.mockResolvedValue(baseUsage);
    const { usageRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(usageRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/usage',
      payload: {
        userId: 'user_1',
        date: '2026-02-16',
        dictations: 5,
        words: 250,
        tokensUsed: 1200,
      },
    });
    expect(res.statusCode).toBe(200);
    expect(repoMock.upsert).toHaveBeenCalled();
  });

  it('POST /usage rejects invalid input', async () => {
    const { usageRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(usageRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/usage',
      payload: { date: 'invalid' },
    });
    expect(res.statusCode).toBe(400);
  });

  it('POST /usage/check-limits returns allowed status', async () => {
    repoMock.getMonthlyUsage.mockResolvedValue({ tokens: 500, words: 200, dictations: 5 });
    const { usageRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(usageRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/usage/check-limits',
      payload: { userId: 'user_1', plan: 'free' },
    });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.allowed).toBe(true);
    expect(data.exceeded).toEqual([]);
  });

  it('POST /usage/check-limits detects exceeded limits', async () => {
    repoMock.getMonthlyUsage.mockResolvedValue({ tokens: 20000, words: 10000, dictations: 200 });
    const { usageRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(usageRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/usage/check-limits',
      payload: { userId: 'user_1', plan: 'free' },
    });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.allowed).toBe(false);
    expect(data.exceeded.length).toBeGreaterThan(0);
  });

  it('POST /usage/check-limits rejects invalid plan', async () => {
    const { usageRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(usageRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/usage/check-limits',
      payload: { userId: 'user_1', plan: 'invalid' },
    });
    expect(res.statusCode).toBe(400);
  });
});
