/**
 * ZohoCampaignsProvider Unit Tests
 *
 * Tests for OAuth 2.0 flow, API calls, and error handling.
 */

import { ZohoCampaignsProvider } from '../ZohoCampaignsProvider';

// Mock axios
jest.mock('axios', () => ({
  create: jest.fn(() => ({
    interceptors: {
      request: { use: jest.fn() },
      response: { use: jest.fn() },
    },
    request: jest.fn(),
    get: jest.fn(),
    post: jest.fn(),
  })),
  post: jest.fn(),
}));

describe('ZohoCampaignsProvider', () => {
  const mockAccessToken = 'mock-access-token';
  const mockRefreshToken = 'mock-refresh-token';
  const mockClientId = 'test-client-id';
  const mockClientSecret = 'test-client-secret';
  const mockOnTokenRefresh = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('getAuthorizationUrl', () => {
    it('should generate correct OAuth authorization URL for US data center', () => {
      const config = {
        clientId: mockClientId,
        clientSecret: mockClientSecret,
        redirectUri: 'http://localhost:3101/api/email-integration/zoho/callback',
        scope: 'ZohoCampaigns.campaign.ALL,ZohoCampaigns.contact.ALL',
      };
      const state = Buffer.from(JSON.stringify({ companyId: '123', dataCenter: 'com' })).toString('base64');

      const url = ZohoCampaignsProvider.getAuthorizationUrl(config, state, 'com');

      expect(url).toContain('https://accounts.zoho.com/oauth/v2/auth');
      expect(url).toContain('client_id=' + mockClientId);
      expect(url).toContain('response_type=code');
      expect(url).toContain('access_type=offline');
      expect(url).toContain('prompt=consent');
      expect(url).toContain('state=' + state);
    });

    it('should generate correct OAuth authorization URL for EU data center', () => {
      const config = {
        clientId: mockClientId,
        clientSecret: mockClientSecret,
        redirectUri: 'http://localhost:3101/api/email-integration/zoho/callback',
      };
      const state = 'test-state';

      const url = ZohoCampaignsProvider.getAuthorizationUrl(config, state, 'eu');

      expect(url).toContain('https://accounts.zoho.eu/oauth/v2/auth');
    });

    it('should generate correct OAuth authorization URL for India data center', () => {
      const config = {
        clientId: mockClientId,
        clientSecret: mockClientSecret,
        redirectUri: 'http://localhost:3101/api/email-integration/zoho/callback',
      };
      const state = 'test-state';

      const url = ZohoCampaignsProvider.getAuthorizationUrl(config, state, 'in');

      expect(url).toContain('https://accounts.zoho.in/oauth/v2/auth');
    });
  });

  describe('constructor', () => {
    it('should create provider instance with default US data center', () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      expect(provider).toBeDefined();
    });

    it('should create provider instance with custom data center', () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'eu',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      expect(provider).toBeDefined();
    });

    it('should accept token refresh callback', () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret },
        mockOnTokenRefresh
      );

      expect(provider).toBeDefined();
    });
  });

  describe('setTokenExpiresAt', () => {
    it('should set token expiry time', () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      const expiryDate = new Date(Date.now() + 3600000); // 1 hour from now
      provider.setTokenExpiresAt(expiryDate);

      // Method should not throw
      expect(provider).toBeDefined();
    });
  });

  describe('verifyConnection', () => {
    it('should return true when connection is valid', async () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      // Mock getAccountInfo to not throw
      provider.getAccountInfo = jest.fn().mockResolvedValue({ email: 'test@example.com' });

      const result = await provider.verifyConnection();

      expect(result).toBe(true);
    });

    it('should return false when connection fails', async () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      // Mock getAccountInfo to throw
      provider.getAccountInfo = jest.fn().mockRejectedValue(new Error('Invalid token'));

      const result = await provider.verifyConnection();

      expect(result).toBe(false);
    });
  });

  describe('healthCheck', () => {
    it('should return ok status when connection is valid', async () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      // Mock getLists to not throw
      provider.getLists = jest.fn().mockResolvedValue([]);

      const result = await provider.healthCheck();

      expect(result.status).toBe('ok');
    });

    it('should return error status when connection fails', async () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      // Mock getLists to throw
      provider.getLists = jest.fn().mockRejectedValue(new Error('Connection failed'));

      const result = await provider.healthCheck();

      expect(result.status).toBe('error');
      expect(result.message).toContain('Connection failed');
    });
  });

  describe('getSenders', () => {
    it('should return empty array (Zoho manages senders in UI)', async () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      const result = await provider.getSenders();

      expect(result).toEqual([]);
    });
  });

  describe('createSender', () => {
    it('should throw error (Zoho does not support sender creation via API)', async () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      await expect(provider.createSender({ name: 'Test', email: 'test@example.com' }))
        .rejects.toThrow('Sender creation is not supported via Zoho Campaigns API');
    });
  });

  describe('sendTestEmail', () => {
    it('should throw error (Zoho does not support test email via API)', async () => {
      const provider = new ZohoCampaignsProvider(
        mockAccessToken,
        mockRefreshToken,
        'com',
        { clientId: mockClientId, clientSecret: mockClientSecret }
      );

      await expect(provider.sendTestEmail('campaign-key', 'test@example.com'))
        .rejects.toThrow('Test email sending is not supported via Zoho Campaigns API');
    });
  });
});

describe('Data Center Configuration', () => {
  it('should have all supported data centers', () => {
    const supportedDataCenters = ['com', 'eu', 'in', 'au', 'jp', 'cn', 'ca'];

    supportedDataCenters.forEach(dc => {
      const config = {
        clientId: 'test',
        clientSecret: 'test',
        redirectUri: 'http://localhost:3101/callback',
      };
      const state = 'test-state';

      // Should not throw for any supported data center
      expect(() => ZohoCampaignsProvider.getAuthorizationUrl(config, state, dc)).not.toThrow();
    });
  });
});

describe('OAuth State Parameter', () => {
  it('should encode company ID and data center in state', () => {
    const config = {
      clientId: mockClientId,
      clientSecret: mockClientSecret,
      redirectUri: 'http://localhost:3101/callback',
    };
    const stateData = { companyId: 'company-123', dataCenter: 'eu' };
    const state = Buffer.from(JSON.stringify(stateData)).toString('base64');

    const url = ZohoCampaignsProvider.getAuthorizationUrl(config, state, 'eu');

    expect(url).toContain('state=' + state);

    // Verify we can decode it back
    const decodedState = JSON.parse(Buffer.from(state, 'base64').toString());
    expect(decodedState.companyId).toBe('company-123');
    expect(decodedState.dataCenter).toBe('eu');
  });
});