/**
 * Tests for GET/POST /api/licenses
 */

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

const mockRequireAdmin = vi.fn();
vi.mock('@/lib/auth-server', () => ({
  requireAdmin: (...args: unknown[]) => mockRequireAdmin(...args),
  getCurrentUser: (...args: unknown[]) => mockRequireAdmin(...args),
  getCurrentUserFromRequest: (...args: unknown[]) => mockRequireAdmin(...args),
}));

const mockGetUserLicenses = vi.fn();
const mockGenerateLicense = vi.fn();
const mockRevokeLicense = vi.fn();
const mockDeactivateLicenseDevice = vi.fn();
vi.mock('@/lib/billing-client', () => ({
  getUserLicenses: (...args: unknown[]) => mockGetUserLicenses(...args),
  generateLicense: (...args: unknown[]) => mockGenerateLicense(...args),
  revokeLicense: (...args: unknown[]) => mockRevokeLicense(...args),
  deactivateLicenseDevice: (...args: unknown[]) => mockDeactivateLicenseDevice(...args),
}));

import { GET, POST } from '@/app/api/licenses/route';

async function makeGet(params: Record<string, string> = {}) {
  const { NextRequest } = await import('next/server');
  const qs = new URLSearchParams(params).toString();
  return GET(new NextRequest(new Request(`http://localhost:3001/api/licenses?${qs}`)));
}

async function makePost(body: object) {
  const { NextRequest } = await import('next/server');
  return POST(
    new NextRequest(
      new Request('http://localhost:3001/api/licenses', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      })
    )
  );
}

describe('GET /api/licenses', () => {
  beforeEach(() => vi.clearAllMocks());

  it('returns 401 when not admin', async () => {
    mockRequireAdmin.mockResolvedValue(null);
    const res = await makeGet({ userId: 'u1' });
    expect(res.status).toBe(401);
  });

  it('returns 400 when userId missing', async () => {
    mockRequireAdmin.mockResolvedValue({ id: 'admin1' });
    const res = await makeGet();
    expect(res.status).toBe(400);
    const data = await res.json();
    expect(data.error).toContain('userId');
  });

  it('returns licenses for user', async () => {
    mockRequireAdmin.mockResolvedValue({ id: 'admin1' });
    mockGetUserLicenses.mockResolvedValue({
      licenses: [{ key: 'LYSNR-ABCD', status: 'active' }],
    });

    const res = await makeGet({ userId: 'usr_1' });
    expect(res.status).toBe(200);
    const data = await res.json();
    expect(data.licenses).toHaveLength(1);
  });

  it('returns 500 on service error', async () => {
    mockRequireAdmin.mockResolvedValue({ id: 'admin1' });
    mockGetUserLicenses.mockRejectedValue(new Error('Service down'));

    const res = await makeGet({ userId: 'usr_1' });
    expect(res.status).toBe(500);
  });
});

describe('POST /api/licenses', () => {
  beforeEach(() => vi.clearAllMocks());

  it('returns 401 when not admin', async () => {
    mockRequireAdmin.mockResolvedValue(null);
    const res = await makePost({ userId: 'u1' });
    expect(res.status).toBe(401);
  });

  it('generates new license by default', async () => {
    mockRequireAdmin.mockResolvedValue({ id: 'admin1' });
    mockGenerateLicense.mockResolvedValue({ key: 'LYSNR-NEW1', status: 'active' });

    const res = await makePost({ userId: 'usr_1', plan: 'pro' });
    expect(res.status).toBe(201);
    const data = await res.json();
    expect(data.key).toBe('LYSNR-NEW1');
  });

  it('revokes license when action is revoke', async () => {
    mockRequireAdmin.mockResolvedValue({ id: 'admin1' });
    mockRevokeLicense.mockResolvedValue({ success: true });

    const res = await makePost({ action: 'revoke', key: 'LYSNR-ABCD' });
    expect(res.status).toBe(200);
    expect(mockRevokeLicense).toHaveBeenCalledWith('LYSNR-ABCD');
  });

  it('deactivates device when action is deactivate', async () => {
    mockRequireAdmin.mockResolvedValue({ id: 'admin1' });
    mockDeactivateLicenseDevice.mockResolvedValue({ success: true });

    const res = await makePost({ action: 'deactivate', key: 'LYSNR-ABCD', deviceId: 'dev1' });
    expect(res.status).toBe(200);
    expect(mockDeactivateLicenseDevice).toHaveBeenCalledWith('LYSNR-ABCD', 'dev1');
  });

  it('returns 500 on error', async () => {
    mockRequireAdmin.mockResolvedValue({ id: 'admin1' });
    mockGenerateLicense.mockRejectedValue(new Error('Limit reached'));

    const res = await makePost({ userId: 'u1' });
    expect(res.status).toBe(500);
  });
});
