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

// Mock next/server
vi.mock('next/server', () => ({
  NextResponse: {
    json: (body, init) => ({
      _body: body,
      status: init?.status || 200,
      json: () => Promise.resolve(body),
    }),
  },
}));

// Mock cookies + localStorage mock for auth_token
const mockGet = vi.fn();
vi.mock('next/headers', () => ({
  cookies: vi.fn(() => Promise.resolve({ get: mockGet })),
}));

// Mock JWT
vi.mock('@/lib/auth/jwt', () => ({
  verifyToken: vi.fn(),
}));

// Mock dashboard session
vi.mock('@/lib/auth/dashboardSession', () => ({
  getDashboardAuthSession: vi.fn(),
}));

// Mock getSettings
vi.mock('@/lib/localDb', () => ({
  getSettings: vi.fn(() => Promise.resolve({
    requireLogin: true,
    authMode: 'password',
    password: true,
  })),
}));

// Mock OIDC
vi.mock('@/lib/auth/oidc', () => ({
  isOidcConfigured: vi.fn(() => false),
}));

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

  it('returns authenticated user data when JWT is valid', async () => {
    const { verifyToken } = await import('@/lib/auth/jwt');
    verifyToken.mockResolvedValue({ userId: 'user-1', username: 'bob', role: 'admin' });
    mockGet.mockReturnValue({ value: 'valid-jwt' });

    const { GET } = await import('./route.js');
    const res = await GET();

    expect(res.status).toBe(200);
    expect(res._body.displayName).toBe('bob');
    expect(res._body.role).toBe('admin');
    expect(res._body.loginMethod).toBe('Password');
    expect(res._body.requireLogin).toBe(true);
  });

  it('falls back to OIDC session when JWT is invalid', async () => {
    const { verifyToken } = await import('@/lib/auth/jwt');
    verifyToken.mockResolvedValue(null);

    const { getDashboardAuthSession } = await import('@/lib/auth/dashboardSession');
    getDashboardAuthSession.mockResolvedValue({
      oidcName: 'Alice',
      oidcEmail: 'alice@example.com',
      oidc: true,
    });
    mockGet.mockReturnValue({ value: 'oidc-token' });

    const { GET } = await import('./route.js');
    const res = await GET();

    expect(res.status).toBe(200);
    expect(res._body.loginMethod).toBe('OIDC');
    expect(res._body.oidcLogin).toBe(true);
    expect(res._body.oidcName).toBe('Alice');
  });

  it('returns defaults when no auth at all', async () => {
    const { verifyToken } = await import('@/lib/auth/jwt');
    verifyToken.mockResolvedValue(null);

    const { getDashboardAuthSession } = await import('@/lib/auth/dashboardSession');
    getDashboardAuthSession.mockResolvedValue({ oidc: false });
    mockGet.mockReturnValue(undefined);

    const { GET } = await import('./route.js');
    const res = await GET();

    expect(res.status).toBe(200);
    expect(res._body.displayName).toBe('Password user');
    expect(res._body.loginMethod).toBe('Password');
  });

  it('returns default state on error', async () => {
    const { verifyToken } = await import('@/lib/auth/jwt');
    verifyToken.mockRejectedValue(new Error('boom'));

    // getSettings will also throw since no mock
    const { getSettings } = await import('@/lib/localDb');
    getSettings.mockRejectedValue(new Error('DB error'));

    const { GET } = await import('./route.js');
    const res = await GET();

    expect(res.status).toBe(200);
    expect(res._body.requireLogin).toBe(true);
    expect(res._body.authMode).toBe('password');
  });
});
