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

const { authenticateAuthUserMock, issueJwtTokenMock } = vi.hoisted(() => ({
  authenticateAuthUserMock: vi.fn(),
  issueJwtTokenMock: vi.fn(),
}));

vi.mock('@/lib/auth', () => ({
  authenticateAuthUser: authenticateAuthUserMock,
}));

vi.mock('@/lib/jwt', () => ({
  issueJwtToken: issueJwtTokenMock,
}));

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

describe('Unit — /api/auth/login route', () => {
  beforeEach(() => {
    vi.resetAllMocks();
    process.env.FRONTEND_ORIGIN = 'http://localhost:3000';
    authenticateAuthUserMock.mockResolvedValue(null);
    issueJwtTokenMock.mockReturnValue('token-123');
  });

  it('returns 400 for invalid JSON', async () => {
    const res = await POST(
      new Request('http://localhost/api/auth/login', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: '{',
      }),
    );

    expect(res.status).toBe(400);
    expect(await res.json()).toEqual({ message: 'Invalid JSON payload' });
  });

  it('returns 400 for validation failure', async () => {
    const res = await POST(
      new Request('http://localhost/api/auth/login', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ username: '' }),
      }),
    );

    expect(res.status).toBe(400);
    const body = await res.json();
    expect(body.message).toBe('Validation failed');
  });

  it('returns 401 when credentials are invalid', async () => {
    authenticateAuthUserMock.mockResolvedValue(null);

    const res = await POST(
      new Request('http://localhost/api/auth/login', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ username: 'admin', password: 'bad' }),
      }),
    );

    expect(res.status).toBe(401);
    expect(await res.json()).toEqual({ message: 'Invalid credentials' });
    expect(issueJwtTokenMock).not.toHaveBeenCalled();
  });

  it('returns 200 and sets auth cookie on success', async () => {
    authenticateAuthUserMock.mockResolvedValue({ username: 'admin', role: 'admin' });

    const res = await POST(
      new Request('http://localhost/api/auth/login', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ username: 'admin', password: 'secret' }),
      }),
    );

    expect(res.status).toBe(200);
    expect(issueJwtTokenMock).toHaveBeenCalledWith('admin', 'admin');

    const body = await res.json();
    expect(body).toEqual({
      message: 'Login successful',
      token: 'token-123',
      tokenType: 'Bearer',
      user: { username: 'admin', role: 'admin' },
    });

    expect(res.headers.get('Access-Control-Allow-Origin')).toBe('http://localhost:3000');
    expect(res.headers.get('Access-Control-Allow-Credentials')).toBe('true');
    expect(res.headers.get('set-cookie')).toContain('auth_token=token-123');
  });

  it('returns 500 when auth backend fails', async () => {
    authenticateAuthUserMock.mockRejectedValue(new Error('boom'));

    const res = await POST(
      new Request('http://localhost/api/auth/login', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ username: 'admin', password: 'secret' }),
      }),
    );

    expect(res.status).toBe(500);
    expect(await res.json()).toEqual({ message: 'boom' });
  });
});