import { describe, it, expect, beforeEach, vi } from 'vitest';
import { GET } from '@/app/api/auth/verify-email/route';
import { NextRequest } from 'next/server';
import { db } from '@/lib/db';

// Mock the database
vi.mock('@/lib/db', () => ({
  db: {
    verificationToken: {
      findUnique: vi.fn(),
      delete: vi.fn(),
    },
    user: {
      update: vi.fn(),
    },
  },
}));

describe('/api/auth/verify-email', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should verify email with valid token', async () => {
    // Arrange
    const mockToken = {
      identifier: 'test@example.com',
      token: 'valid_token_123',
      expires: new Date(Date.now() + 24 * 60 * 60 * 1000), // Future date
    };

    vi.mocked(db.verificationToken.findUnique).mockResolvedValue(mockToken as any);
    vi.mocked(db.user.update).mockResolvedValue({} as any);
    vi.mocked(db.verificationToken.delete).mockResolvedValue({} as any);

    const request = new NextRequest(
      'http://localhost:3000/api/auth/verify-email?token=valid_token_123&email=test@example.com'
    );

    // Act
    const response = await GET(request);

    // Assert
    expect(response.status).toBe(307); // Redirect
    expect(response.headers.get('location')).toContain('/dashboard?verified=true');
    expect(db.user.update).toHaveBeenCalledWith({
      where: { email: 'test@example.com' },
      data: { emailVerified: expect.any(Date) },
    });
    expect(db.verificationToken.delete).toHaveBeenCalled();
  });

  it('should reject verification with missing token', async () => {
    // Arrange
    const request = new NextRequest(
      'http://localhost:3000/api/auth/verify-email?email=test@example.com'
    );

    // Act
    const response = await GET(request);

    // Assert
    expect(response.status).toBe(307);
    expect(response.headers.get('location')).toContain('/auth/error?error=InvalidToken');
    expect(db.verificationToken.findUnique).not.toHaveBeenCalled();
  });

  it('should reject verification with missing email', async () => {
    // Arrange
    const request = new NextRequest(
      'http://localhost:3000/api/auth/verify-email?token=valid_token_123'
    );

    // Act
    const response = await GET(request);

    // Assert
    expect(response.status).toBe(307);
    expect(response.headers.get('location')).toContain('/auth/error?error=InvalidToken');
    expect(db.verificationToken.findUnique).not.toHaveBeenCalled();
  });

  it('should reject verification with invalid token', async () => {
    // Arrange
    vi.mocked(db.verificationToken.findUnique).mockResolvedValue(null);

    const request = new NextRequest(
      'http://localhost:3000/api/auth/verify-email?token=invalid_token&email=test@example.com'
    );

    // Act
    const response = await GET(request);

    // Assert
    expect(response.status).toBe(307);
    expect(response.headers.get('location')).toContain('/auth/error?error=InvalidToken');
    expect(db.user.update).not.toHaveBeenCalled();
  });

  it('should reject verification with expired token', async () => {
    // Arrange
    const mockToken = {
      identifier: 'test@example.com',
      token: 'expired_token_123',
      expires: new Date(Date.now() - 24 * 60 * 60 * 1000), // Past date
    };

    vi.mocked(db.verificationToken.findUnique).mockResolvedValue(mockToken as any);
    vi.mocked(db.verificationToken.delete).mockResolvedValue({} as any);

    const request = new NextRequest(
      'http://localhost:3000/api/auth/verify-email?token=expired_token_123&email=test@example.com'
    );

    // Act
    const response = await GET(request);

    // Assert
    expect(response.status).toBe(307);
    expect(response.headers.get('location')).toContain('/auth/error?error=TokenExpired');
    expect(db.verificationToken.delete).toHaveBeenCalled(); // Clean up expired token
    expect(db.user.update).not.toHaveBeenCalled();
  });

  it('should handle database errors gracefully', async () => {
    // Arrange
    vi.mocked(db.verificationToken.findUnique).mockRejectedValue(new Error('Database error'));

    const request = new NextRequest(
      'http://localhost:3000/api/auth/verify-email?token=valid_token_123&email=test@example.com'
    );

    // Act
    const response = await GET(request);

    // Assert
    expect(response.status).toBe(307);
    expect(response.headers.get('location')).toContain('/auth/error?error=VerificationFailed');
  });
});
