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

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

const repoMock = {
  list: vi.fn(),
  getByName: vi.fn(),
  create: vi.fn(),
  update: vi.fn(),
  getDefaults: vi.fn(),
};

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

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

const basePlan = {
  id: 'plan_lysnrai_pro',
  productId: 'lysnrai',
  name: 'pro',
  displayName: 'Pro',
  price: 9.99,
  tokens: 100000,
  words: 50000,
  dictations: 5000,
  features: ['basic_dictation'],
  active: true,
  createdAt: '2026-02-16T00:00:00Z',
  updatedAt: '2026-02-16T00:00:00Z',
};

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

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

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

    const res = await app.inject({ method: 'GET', url: '/api/plans' });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.plans).toHaveLength(1);
    expect(data.plans[0].name).toBe('pro');
  });

  it('GET /plans/:name returns plan by name', async () => {
    repoMock.getByName.mockResolvedValue(basePlan);
    const { planRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(planRoutes, { prefix: '/api' });

    const res = await app.inject({ method: 'GET', url: '/api/plans/pro' });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.name).toBe('pro');
  });

  it('GET /plans/:name falls back to defaults', async () => {
    repoMock.getByName.mockResolvedValue(null);
    repoMock.getDefaults.mockReturnValue([
      { ...basePlan, name: 'free', displayName: 'Free' },
    ]);
    const { planRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(planRoutes, { prefix: '/api' });

    const res = await app.inject({ method: 'GET', url: '/api/plans/free' });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.name).toBe('free');
  });

  it('POST /plans creates a plan', async () => {
    repoMock.create.mockResolvedValue(basePlan);
    const { planRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(planRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/plans',
      payload: {
        name: 'pro',
        displayName: 'Pro',
        price: 9.99,
        tokens: 100000,
        words: 50000,
        dictations: 5000,
      },
    });
    expect(res.statusCode).toBe(201);
  });

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

    const res = await app.inject({
      method: 'POST',
      url: '/api/plans',
      payload: { price: -1 },
    });
    expect(res.statusCode).toBe(400);
  });

  it('PUT /plans/:id updates a plan', async () => {
    repoMock.update.mockResolvedValue({ ...basePlan, price: 14.99 });
    const { planRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(planRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'PUT',
      url: '/api/plans/plan_lysnrai_pro',
      payload: { price: 14.99 },
    });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.price).toBe(14.99);
  });

  it('PUT /plans/:id returns 404 when not found', async () => {
    repoMock.update.mockResolvedValue(null);
    const { planRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(planRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'PUT',
      url: '/api/plans/nonexistent',
      payload: { price: 14.99 },
    });
    expect(res.statusCode).toBe(404);
  });

  it('POST /plans/seed seeds default plans', async () => {
    repoMock.getDefaults.mockReturnValue([basePlan]);
    repoMock.getByName.mockResolvedValue(null);
    repoMock.create.mockResolvedValue(basePlan);
    const { planRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(planRoutes, { prefix: '/api' });

    const res = await app.inject({ method: 'POST', url: '/api/plans/seed' });
    expect(res.statusCode).toBe(201);
    const data = JSON.parse(res.body);
    expect(data.plans).toHaveLength(1);
  });
});
