/*
Copyright (c) 2025 Bernier LLC

This file is licensed to the client under a limited-use license.
The client may use and modify this code *only within the scope of the project it was delivered for*.
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
*/

import { SendGridProvider } from '../src/providers/SendGridProvider';
import { MailgunProvider } from '../src/providers/MailgunProvider';
import { SESProvider } from '../src/providers/SESProvider';
import { SMTPProvider } from '../src/providers/SMTPProvider';
import { SenderIdentity, EmailProvider, SenderStatus } from '../src/types';
import { createFetchMock } from './__mocks__/fetch-mock';

describe('Provider Tests with HTTP Mocking', () => {
  const mockSender: SenderIdentity = {
    id: 'test-123',
    email: 'test@example.com',
    name: 'Test User',
    replyToEmail: 'reply@example.com',
    replyToName: 'Reply User',
    domain: 'example.com',
    provider: EmailProvider.SENDGRID,
    status: SenderStatus.PENDING,
    isDefault: false,
    isActive: true,
    verificationAttempts: 0,
    createdAt: new Date(),
    updatedAt: new Date()
  };

  let fetchMock: ReturnType<typeof createFetchMock>;
  let originalFetch: typeof fetch;

  beforeEach(() => {
    fetchMock = createFetchMock();
    originalFetch = global.fetch;
    global.fetch = fetchMock.getFetchMock() as typeof fetch;
  });

  afterEach(() => {
    global.fetch = originalFetch;
    fetchMock.clear();
  });

  describe('SendGridProvider', () => {
    describe('Success Cases', () => {
      it('should successfully verify sender with valid API key', async () => {
        const provider = new SendGridProvider('test-api-key');

        fetchMock.mockSuccess(
          'https://api.sendgrid.com/v3/verified_senders',
          {
            id: 'sendgrid-123',
            from_email: 'test@example.com',
            verified: false,
            nickname: 'Test User'
          }
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(true);
        expect(result.data).toBeDefined();
        expect(result.data?.providerId).toBe('sendgrid-123');
        expect(result.data?.metadata).toBeDefined();

        const history = fetchMock.getCallHistory();
        expect(history).toHaveLength(1);
        expect(history[0].url).toBe('https://api.sendgrid.com/v3/verified_senders');
        expect(history[0].method).toBe('POST');
      });

      it('should include sender details in request', async () => {
        const provider = new SendGridProvider('test-api-key');

        fetchMock.mockSuccess(
          'https://api.sendgrid.com/v3/verified_senders',
          { id: 'sendgrid-456', verified: false }
        );

        await provider.verifySender(mockSender);

        const history = fetchMock.getCallHistory();
        const requestBody = JSON.parse(history[0].body || '{}');

        expect(requestBody.nickname).toBe('Test User');
        expect(requestBody.from_email).toBe('test@example.com');
        expect(requestBody.from_name).toBe('Test User');
        expect(requestBody.reply_to).toBe('reply@example.com');
        expect(requestBody.reply_to_name).toBe('Reply User');
      });
    });

    describe('Error Cases', () => {
      it('should fail without API key', async () => {
        const provider = new SendGridProvider('');
        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toContain('API key');
      });

      it('should handle 401 Unauthorized error', async () => {
        const provider = new SendGridProvider('invalid-key');

        fetchMock.mockError(
          'https://api.sendgrid.com/v3/verified_senders',
          401,
          {
            errors: [{ message: 'Unauthorized - Invalid API key' }]
          }
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toBe('SendGrid verification failed');
        expect(result.errors).toContain('Unauthorized - Invalid API key');
      });

      it('should handle 403 Forbidden error', async () => {
        const provider = new SendGridProvider('test-key');

        fetchMock.mockError(
          'https://api.sendgrid.com/v3/verified_senders',
          403,
          {
            errors: [{ message: 'Forbidden - Insufficient permissions' }]
          }
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toBe('SendGrid verification failed');
        expect(result.errors).toContain('Forbidden - Insufficient permissions');
      });

      it('should handle 404 Not Found error', async () => {
        const provider = new SendGridProvider('test-key');

        fetchMock.mockError(
          'https://api.sendgrid.com/v3/verified_senders',
          404,
          {
            errors: [{ message: 'Resource not found' }]
          }
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toBe('SendGrid verification failed');
        expect(result.errors).toContain('Resource not found');
      });

      it('should handle 429 Rate Limit error', async () => {
        const provider = new SendGridProvider('test-key');

        fetchMock.mockError(
          'https://api.sendgrid.com/v3/verified_senders',
          429,
          {
            errors: [{ message: 'Rate limit exceeded' }]
          }
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toBe('SendGrid verification failed');
        expect(result.errors).toContain('Rate limit exceeded');
      });

      it('should handle 500 Internal Server Error', async () => {
        const provider = new SendGridProvider('test-key');

        fetchMock.mockError(
          'https://api.sendgrid.com/v3/verified_senders',
          500,
          {
            errors: [{ message: 'Internal server error' }]
          }
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toBe('SendGrid verification failed');
        expect(result.errors).toContain('Internal server error');
      });

      it('should handle network errors', async () => {
        const provider = new SendGridProvider('test-key');

        fetchMock.mockNetworkError(
          'https://api.sendgrid.com/v3/verified_senders',
          'Connection timeout'
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toBe('SendGrid verification failed');
        expect(result.errors).toContain('Connection timeout');
      });

      it('should handle connection refused', async () => {
        const provider = new SendGridProvider('test-key');

        fetchMock.mockNetworkError(
          'https://api.sendgrid.com/v3/verified_senders',
          'Connection refused'
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toBe('SendGrid verification failed');
        expect(result.errors).toContain('Connection refused');
      });

      it('should handle malformed response', async () => {
        const provider = new SendGridProvider('test-key');

        fetchMock.mockError(
          'https://api.sendgrid.com/v3/verified_senders',
          400,
          {} // Missing errors array
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(false);
        expect(result.error).toBe('SendGrid verification failed');
        expect(result.errors).toContain('SendGrid API error');
      });

      it('should handle response without ID', async () => {
        const provider = new SendGridProvider('test-key');

        fetchMock.mockSuccess(
          'https://api.sendgrid.com/v3/verified_senders',
          {
            // Missing id field
            verified: false
          }
        );

        const result = await provider.verifySender(mockSender);

        expect(result.success).toBe(true);
        expect(result.data?.providerId).toBe('');
      });
    });
  });

  describe('MailgunProvider', () => {
    it('should succeed without API key (domain-only verification)', async () => {
      const provider = new MailgunProvider('');
      const result = await provider.verifySender(mockSender);

      expect(result.success).toBe(true);
      expect(result.data).toBeDefined();
      expect(result.data?.note).toContain('Mailgun does not require');
    });

    it('should succeed with API key', async () => {
      const provider = new MailgunProvider('test-key');
      const result = await provider.verifySender(mockSender);

      expect(result.success).toBe(true);
      expect(result.data).toBeDefined();
    });

    it('should note domain-level verification', async () => {
      const provider = new MailgunProvider('mg-api-key');
      const result = await provider.verifySender(mockSender);

      expect(result.success).toBe(true);
      expect(result.data?.note).toContain('individual sender verification');
    });
  });

  describe('SESProvider', () => {
    it('should succeed without credentials (stub implementation)', async () => {
      const provider = new SESProvider('', '', '');
      const result = await provider.verifySender(mockSender);

      expect(result.success).toBe(true);
      expect(result.data).toBeDefined();
      expect(result.data?.note).toContain('SES verification stubbed');
    });

    it('should succeed with credentials', async () => {
      const provider = new SESProvider('AKIAIOSFODNN7EXAMPLE', 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', 'us-east-1');
      const result = await provider.verifySender(mockSender);

      expect(result.success).toBe(true);
      expect(result.data).toBeDefined();
    });

    it('should note pending AWS SDK integration', async () => {
      const provider = new SESProvider('key', 'secret', 'us-west-2');
      const result = await provider.verifySender(mockSender);

      expect(result.success).toBe(true);
      expect(result.data?.note).toContain('AWS SDK integration pending');
    });
  });

  describe('SMTPProvider', () => {
    it('should always succeed (no verification required)', async () => {
      const provider = new SMTPProvider();
      const result = await provider.verifySender(mockSender);

      expect(result.success).toBe(true);
      expect(result.data).toBeDefined();
    });

    it('should note SMTP does not require verification', async () => {
      const provider = new SMTPProvider();
      const result = await provider.verifySender(mockSender);

      expect(result.success).toBe(true);
      expect(result.data?.note).toContain('SMTP does not require');
    });
  });
});
