import crypto from 'crypto';
import type { NextFunction, Request, Response } from 'express';
import { prismaMock } from '../../setup';
import { authenticateApiKey } from '../../../middleware/auth';

function responseMock(): Response {
  const response = {
    status: jest.fn(),
    json: jest.fn(),
  } as unknown as Response;
  (response.status as jest.Mock).mockReturnValue(response);
  return response;
}

function request(overrides: Record<string, string> = {}): Request {
  return {
    headers: {
      authorization: 'Bearer INTL-ABCD-EFGH-IJKL',
      'x-plugin': 'international',
      'x-site-url': 'https://example.com/path',
      ...overrides,
    },
  } as unknown as Request;
}

const activeLicense = {
  id: 'license-id',
  user_id: 'user-id',
  key_hash: crypto.createHash('sha256').update('INTL-ABCD-EFGH-IJKL').digest('hex'),
  plugin: 'international',
  plan_tier: 'professional',
  status: 'active',
  execution_mode: 'mock',
  expires_at: new Date('2099-01-01T00:00:00.000Z'),
  activations: [{ site_url: 'https://example.com' }],
  user: {
    id: 'user-id',
    email: 'owner@example.com',
    status: 'active',
    subscriptions: [
      { plugin: 'international', status: 'active', plan_tier: 'professional' },
    ],
  },
};

describe('authenticateApiKey license credentials', () => {
  it('authenticates an active license for its exact plugin and activated site', async () => {
    prismaMock.license.findUnique.mockResolvedValue(activeLicense as any);
    const req = request();
    const res = responseMock();
    const next = jest.fn() as NextFunction;

    await authenticateApiKey(req, res, next);

    expect(prismaMock.license.findUnique).toHaveBeenCalledWith(expect.objectContaining({
      where: { key_hash: activeLicense.key_hash },
    }));
    expect(req.user).toMatchObject({ userId: 'user-id', plugin: 'international' });
    expect(req.license).toMatchObject({
      id: 'license-id',
      plugin: 'international',
      executionMode: 'mock',
    });
    expect(req.apiKey).toBeUndefined();
    expect(next).toHaveBeenCalledTimes(1);
  });

  it.each([
    ['missing plugin', { 'x-plugin': '' }, 401, 'PLUGIN_REQUIRED'],
    ['missing site', { 'x-site-url': '' }, 401, 'SITE_URL_REQUIRED'],
    ['wrong plugin', {}, 403, 'LICENSE_PLUGIN_MISMATCH'],
    ['wrong site', {}, 403, 'LICENSE_SITE_MISMATCH'],
    ['missing owner', {}, 403, 'LICENSE_OWNER_REQUIRED'],
    ['expired', {}, 403, 'LICENSE_EXPIRED'],
  ])('rejects %s', async (_label, overrides, status, code) => {
    const license = structuredClone(activeLicense) as any;
    if (code === 'LICENSE_PLUGIN_MISMATCH') license.plugin = 'translate';
    if (code === 'LICENSE_SITE_MISMATCH') license.activations = [{ site_url: 'https://other.example' }];
    if (code === 'LICENSE_OWNER_REQUIRED') {
      license.user_id = null;
      license.user = null;
    }
    if (code === 'LICENSE_EXPIRED') license.expires_at = new Date('2000-01-01T00:00:00.000Z');
    prismaMock.license.findUnique.mockResolvedValue(license);
    const req = request(overrides as Record<string, string>);
    const res = responseMock();
    const next = jest.fn() as NextFunction;

    await authenticateApiKey(req, res, next);

    expect(res.status).toHaveBeenCalledWith(status);
    expect(res.json).toHaveBeenCalledWith(expect.objectContaining({
      error: expect.objectContaining({ code }),
    }));
    expect(next).not.toHaveBeenCalled();
  });
});
