import { describe, it, expect, beforeEach, vi } from 'vitest';
import { NextRequest } from 'next/server';

const mockSend = vi.fn();

vi.mock('resend', () => {
  return {
    Resend: class MockResend {
      emails = { send: mockSend };
    },
  };
});

describe('/api/contact', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    vi.unstubAllEnvs();
  });

  async function importRoute() {
    vi.resetModules();
    return await import('@/app/api/contact/route');
  }

  function makeRequest(body: unknown) {
    return new NextRequest('http://localhost:3000/api/contact', {
      method: 'POST',
      body: JSON.stringify(body),
    });
  }

  const validPayload = {
    name: 'Alice',
    email: 'alice@example.com',
    subject: 'Hello',
    message: 'This is a valid message with enough characters.',
  };

  it('should return 200 on valid input', async () => {
    vi.stubEnv('RESEND_API_KEY', '');
    const { POST } = await importRoute();

    const response = await POST(makeRequest(validPayload));
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data.ok).toBe(true);
  });

  it('should return 422 on invalid input', async () => {
    vi.stubEnv('RESEND_API_KEY', '');
    const { POST } = await importRoute();

    const response = await POST(makeRequest({ name: '', email: 'bad', subject: '', message: '' }));

    expect(response.status).toBe(422);
  });

  it('should return 400 on malformed JSON', async () => {
    vi.stubEnv('RESEND_API_KEY', '');
    const { POST } = await importRoute();

    const request = new NextRequest('http://localhost:3000/api/contact', {
      method: 'POST',
      body: 'not-json',
    });
    const response = await POST(request);

    expect(response.status).toBe(400);
  });

  it('should call Resend when API key is set', async () => {
    vi.stubEnv('RESEND_API_KEY', 're_test_key_123');
    mockSend.mockResolvedValue({ id: 'msg-1' });
    const { POST } = await importRoute();

    const response = await POST(makeRequest(validPayload));
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data.ok).toBe(true);
    expect(mockSend).toHaveBeenCalledWith(
      expect.objectContaining({
        from: expect.stringContaining('noreply@llmhosts.com'),
        to: 'hello@llmhosts.com',
        subject: expect.stringContaining(validPayload.subject),
        text: expect.stringContaining(validPayload.message),
      }),
    );
  });

  it('should not call Resend when API key is absent', async () => {
    vi.stubEnv('RESEND_API_KEY', '');
    const { POST } = await importRoute();

    const response = await POST(makeRequest(validPayload));

    expect(response.status).toBe(200);
    expect(mockSend).not.toHaveBeenCalled();
  });

  it('should not fail when Resend throws', async () => {
    vi.stubEnv('RESEND_API_KEY', 're_test_key_123');
    mockSend.mockRejectedValue(new Error('Resend API error'));
    const { POST } = await importRoute();

    const response = await POST(makeRequest(validPayload));
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data.ok).toBe(true);
  });
});
