/**
 * Tests for POST /api/auth/login
 *
 * Covers:
 * - 400 for missing email/password
 * - 401 for invalid credentials (loginViaService rejects)
 * - 200 with tokens and user data on success
 * - Audit log entries for success and failure
 * - 401 when loginViaService throws (inner catch returns 401)
 */

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

// ── Mocks ──────────────────────────────────────────────────────────────

const mockLoginViaService = vi.fn();
const mockLogAudit = vi.fn();
vi.mock('@/lib/platform-client', () => ({
  loginViaService: (...args: unknown[]) => mockLoginViaService(...args),
  logAudit: (...args: unknown[]) => mockLogAudit(...args),
}));

vi.mock('@/lib/product-config', () => ({
  PRODUCT_ID: 'test-product',
  getRequestProductId: () => 'test-product',
}));

import { POST } from '@/app/api/auth/login/route';

// ── Helpers ────────────────────────────────────────────────────────────

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

const loginResult = {
  accessToken: 'access_tok_123',
  refreshToken: 'refresh_tok_456',
  user: {
    id: 'usr_admin_1',
    email: 'admin@example.com',
    displayName: 'Admin User',
    role: 'super_admin',
    plan: 'enterprise',
  },
};

// ── Tests ──────────────────────────────────────────────────────────────

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

  it('returns 400 when email is missing', async () => {
    const res = await callLogin({ password: 'pass123' });
    expect(res.status).toBe(400);
    const data = await res.json();
    expect(data.error).toContain('required');
  });

  it('returns 400 when password is missing', async () => {
    const res = await callLogin({ email: 'admin@example.com' });
    expect(res.status).toBe(400);
  });

  it('returns 400 when both are missing', async () => {
    const res = await callLogin({});
    expect(res.status).toBe(400);
  });

  it('returns 401 for invalid credentials', async () => {
    mockLoginViaService.mockRejectedValue(new Error('Invalid credentials'));
    const res = await callLogin({ email: 'bad@example.com', password: 'wrong' });
    expect(res.status).toBe(401);
    const data = await res.json();
    expect(data.error).toContain('Invalid credentials');
  });

  it('logs audit entry on login failure', async () => {
    mockLoginViaService.mockRejectedValue(new Error('Invalid credentials'));
    await callLogin({ email: 'bad@example.com', password: 'wrong' });
    expect(mockLogAudit).toHaveBeenCalledWith(
      expect.objectContaining({
        userId: 'bad@example.com',
        action: 'login_failed',
        category: 'auth',
      })
    );
  });

  it('returns 200 with tokens and user data on success', async () => {
    mockLoginViaService.mockResolvedValue(loginResult);

    const res = await callLogin({ email: 'admin@example.com', password: 'admin123' });
    expect(res.status).toBe(200);
    const data = await res.json();

    expect(data.accessToken).toBe('access_tok_123');
    expect(data.refreshToken).toBe('refresh_tok_456');
    expect(data.user.id).toBe('usr_admin_1');
    expect(data.user.email).toBe('admin@example.com');
    expect(data.user.role).toBe('super_admin');
  });

  it('logs audit entry on login success', async () => {
    mockLoginViaService.mockResolvedValue(loginResult);

    await callLogin({ email: 'admin@example.com', password: 'admin123' });
    expect(mockLogAudit).toHaveBeenCalledWith(
      expect.objectContaining({
        userId: 'usr_admin_1',
        action: 'login_success',
        category: 'auth',
      })
    );
  });

  it('returns 401 when loginViaService throws', async () => {
    mockLoginViaService.mockRejectedValue(new Error('DB connection failed'));
    const res = await callLogin({ email: 'admin@example.com', password: 'pass' });
    // Inner catch returns 401 for any loginViaService failure
    expect(res.status).toBe(401);
  });
});
