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

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

const repoMock = {
  getByUserId: vi.fn(),
  getByStripeCustomerId: vi.fn(),
  getByStripeCustomerIdAnyProduct: vi.fn(),
  createSubscription: vi.fn(),
  updateSubscription: vi.fn(),
  getPaymentsByUser: vi.fn(),
  createPayment: vi.fn(),
};

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

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

const baseSub = {
  id: 'sub_user_1_123',
  productId: 'lysnrai',
  userId: 'user_1',
  plan: 'pro',
  status: 'active',
  currentPeriodStart: '2026-02-01T00:00:00Z',
  currentPeriodEnd: '2026-03-01T00:00:00Z',
  cancelAtPeriodEnd: false,
  monthlyPrice: 9.99,
  tokensIncluded: 100000,
  tokensUsed: 5000,
  createdAt: '2026-02-01T00:00:00Z',
  updatedAt: '2026-02-01T00:00:00Z',
};

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

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

  it('GET /subscriptions/:userId returns subscription', async () => {
    repoMock.getByUserId.mockResolvedValue(baseSub);
    const { subscriptionRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(subscriptionRoutes, { prefix: '/api' });

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

  it('GET /subscriptions/:userId returns 404 when not found', async () => {
    repoMock.getByUserId.mockResolvedValue(null);
    const { subscriptionRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(subscriptionRoutes, { prefix: '/api' });

    const res = await app.inject({ method: 'GET', url: '/api/subscriptions/user_1' });
    expect(res.statusCode).toBe(404);
  });

  it('POST /subscriptions creates a subscription', async () => {
    repoMock.createSubscription.mockResolvedValue(baseSub);
    const { subscriptionRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(subscriptionRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/subscriptions',
      payload: {
        userId: 'user_1',
        plan: 'pro',
        status: 'active',
        monthlyPrice: 9.99,
        tokensIncluded: 100000,
      },
    });
    expect(res.statusCode).toBe(201);
  });

  it('POST /subscriptions with trial days', async () => {
    repoMock.createSubscription.mockResolvedValue(baseSub);
    const { subscriptionRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(subscriptionRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/subscriptions',
      payload: {
        userId: 'user_1',
        plan: 'pro',
        status: 'trialing',
        monthlyPrice: 9.99,
        tokensIncluded: 100000,
        trialDays: 14,
      },
    });
    expect(res.statusCode).toBe(201);
  });

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

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

  it('PUT /subscriptions/:userId updates subscription', async () => {
    repoMock.getByUserId.mockResolvedValue(baseSub);
    repoMock.updateSubscription.mockResolvedValue({ ...baseSub, plan: 'enterprise' });
    const { subscriptionRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(subscriptionRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'PUT',
      url: '/api/subscriptions/user_1',
      payload: { plan: 'enterprise' },
    });
    expect(res.statusCode).toBe(200);
    const data = JSON.parse(res.body);
    expect(data.plan).toBe('enterprise');
  });

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

    const res = await app.inject({
      method: 'PUT',
      url: '/api/subscriptions/user_1',
      payload: { plan: 'enterprise' },
    });
    expect(res.statusCode).toBe(404);
  });

  it('GET /payments/:userId lists payments', async () => {
    const payment = { id: 'pay_1', amount: 999, currency: 'usd', status: 'succeeded' };
    repoMock.getPaymentsByUser.mockResolvedValue([payment]);
    const { subscriptionRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(subscriptionRoutes, { prefix: '/api' });

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

  it('POST /payments records a payment', async () => {
    const payment = { id: 'pay_1', amount: 999, currency: 'usd', status: 'succeeded' };
    repoMock.createPayment.mockResolvedValue(payment);
    const { subscriptionRoutes } = await import('./routes.js');
    const app = Fastify({ logger: false });
    await app.register(subscriptionRoutes, { prefix: '/api' });

    const res = await app.inject({
      method: 'POST',
      url: '/api/payments',
      payload: {
        userId: 'user_1',
        amount: 999,
        currency: 'usd',
        status: 'succeeded',
        description: 'Pro plan',
        method: 'card',
      },
    });
    expect(res.statusCode).toBe(201);
  });
});
