/**
 * Integration Factory Tests
 *
 * Tests the integration service factory including:
 * - Service creation from metadata
 * - Connection management methods
 * - Data fetching methods
 * - Metadata retrieval
 */
import { describe, it, expect, vi, beforeEach } from 'vitest';
import {
  createIntegrationService,
  getIntegrationService,
  getIntegrationMetadata,
  getAllIntegrationMetadata,
  INTEGRATION_METADATA,
  IntegrationMetadata,
} from './integrationFactory';

// Mock the apiRequest function
vi.mock('./api', () => ({
  apiRequest: vi.fn(),
}));

import { apiRequest } from './api';

describe('integrationFactory', () => {
  const testMetadata: IntegrationMetadata = {
    slug: 'testintegration',
    name: 'Test Integration',
    description: 'A test integration',
    credentials: [{ field: 'api_key', label: 'API Key', placeholder: 'Enter API key' }],
    resources: [
      { name: 'items', endpoint: 'items' },
      { name: 'subitems', endpoint: 'subitems', requiresParent: true, parentResource: 'items' },
    ],
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  // ==========================================================================
  // createIntegrationService Tests
  // ==========================================================================

  describe('createIntegrationService', () => {
    describe('getStatus', () => {
      it('calls correct endpoint', async () => {
        vi.mocked(apiRequest).mockResolvedValue({ connected: true });

        const service = createIntegrationService(testMetadata);
        await service.getStatus();

        expect(apiRequest).toHaveBeenCalledWith('/integrations/testintegration');
      });

      it('returns status response', async () => {
        const mockStatus = { connected: true, connections: [] };
        vi.mocked(apiRequest).mockResolvedValue(mockStatus);

        const service = createIntegrationService(testMetadata);
        const result = await service.getStatus();

        expect(result).toEqual(mockStatus);
      });
    });

    describe('listConnections', () => {
      it('calls connections endpoint', async () => {
        vi.mocked(apiRequest).mockResolvedValue([]);

        const service = createIntegrationService(testMetadata);
        await service.listConnections();

        expect(apiRequest).toHaveBeenCalledWith('/integrations/testintegration/connections');
      });

      it('returns list of connections', async () => {
        const mockConnections = [{ connection_id: 'conn-1', label: 'Main', status: 'connected' }];
        vi.mocked(apiRequest).mockResolvedValue(mockConnections);

        const service = createIntegrationService(testMetadata);
        const result = await service.listConnections();

        expect(result).toEqual(mockConnections);
      });
    });

    describe('createConnection', () => {
      it('posts to connections endpoint with label and credentials', async () => {
        vi.mocked(apiRequest).mockResolvedValue({ connection_id: 'new-conn' });

        const service = createIntegrationService(testMetadata);
        await service.createConnection('My Connection', { api_key: 'test-key' });

        expect(apiRequest).toHaveBeenCalledWith('/integrations/testintegration/connections', {
          method: 'POST',
          body: JSON.stringify({ label: 'My Connection', api_key: 'test-key' }),
        });
      });

      it('returns created connection response', async () => {
        const mockResponse = { connection_id: 'new-conn', label: 'My Connection' };
        vi.mocked(apiRequest).mockResolvedValue(mockResponse);

        const service = createIntegrationService(testMetadata);
        const result = await service.createConnection('My Connection', { api_key: 'key' });

        expect(result).toEqual(mockResponse);
      });
    });

    describe('updateConnection', () => {
      it('puts to connection endpoint with data', async () => {
        vi.mocked(apiRequest).mockResolvedValue({ success: true });

        const service = createIntegrationService(testMetadata);
        await service.updateConnection('conn-1', { label: 'Updated Label' });

        expect(apiRequest).toHaveBeenCalledWith(
          '/integrations/testintegration/connections/conn-1',
          {
            method: 'PUT',
            body: JSON.stringify({ label: 'Updated Label' }),
          },
        );
      });

      it('supports updating credentials', async () => {
        vi.mocked(apiRequest).mockResolvedValue({ success: true });

        const service = createIntegrationService(testMetadata);
        await service.updateConnection('conn-1', {
          credentials: { api_key: 'new-key' },
        });

        expect(apiRequest).toHaveBeenCalledWith(
          '/integrations/testintegration/connections/conn-1',
          {
            method: 'PUT',
            body: JSON.stringify({ credentials: { api_key: 'new-key' } }),
          },
        );
      });
    });

    describe('deleteConnection', () => {
      it('deletes connection endpoint', async () => {
        vi.mocked(apiRequest).mockResolvedValue({ success: true });

        const service = createIntegrationService(testMetadata);
        await service.deleteConnection('conn-1');

        expect(apiRequest).toHaveBeenCalledWith(
          '/integrations/testintegration/connections/conn-1',
          { method: 'DELETE' },
        );
      });

      it('adds confirm_deactivate_workflows query param when option set', async () => {
        vi.mocked(apiRequest).mockResolvedValue({ success: true });

        const service = createIntegrationService(testMetadata);
        await service.deleteConnection('conn-1', { confirmDeactivateWorkflows: true });

        expect(apiRequest).toHaveBeenCalledWith(
          '/integrations/testintegration/connections/conn-1?confirm_deactivate_workflows=1',
          { method: 'DELETE' },
        );
      });

      it('does not add query param when option is false', async () => {
        vi.mocked(apiRequest).mockResolvedValue({ success: true });

        const service = createIntegrationService(testMetadata);
        await service.deleteConnection('conn-1', { confirmDeactivateWorkflows: false });

        expect(apiRequest).toHaveBeenCalledWith(
          '/integrations/testintegration/connections/conn-1',
          { method: 'DELETE' },
        );
      });
    });

    describe('getDataForConnection', () => {
      it('fetches resource for connection', async () => {
        vi.mocked(apiRequest).mockResolvedValue([{ id: 1 }]);

        const service = createIntegrationService(testMetadata);
        await service.getDataForConnection('conn-1', 'items');

        expect(apiRequest).toHaveBeenCalledWith(
          '/integrations/testintegration/connections/conn-1/items',
        );
      });

      it('includes parent ID in endpoint when provided', async () => {
        vi.mocked(apiRequest).mockResolvedValue([{ id: 1 }]);

        const service = createIntegrationService(testMetadata);
        await service.getDataForConnection('conn-1', 'items', 'parent-123');

        expect(apiRequest).toHaveBeenCalledWith(
          '/integrations/testintegration/connections/conn-1/items/parent-123',
        );
      });

      it('includes child resource in endpoint', async () => {
        vi.mocked(apiRequest).mockResolvedValue([{ id: 1 }]);

        const service = createIntegrationService(testMetadata);
        await service.getDataForConnection('conn-1', 'items', 'parent-123', 'subitems');

        expect(apiRequest).toHaveBeenCalledWith(
          '/integrations/testintegration/connections/conn-1/items/parent-123/subitems',
        );
      });

      it('returns typed data', async () => {
        const mockData = [{ id: 1, name: 'Item 1' }];
        vi.mocked(apiRequest).mockResolvedValue(mockData);

        const service = createIntegrationService(testMetadata);
        const result = await service.getDataForConnection<{ id: number; name: string }[]>(
          'conn-1',
          'items',
        );

        expect(result).toEqual(mockData);
      });
    });
  });

  // ==========================================================================
  // INTEGRATION_METADATA Tests
  // ==========================================================================

  describe('INTEGRATION_METADATA', () => {
    it('is an empty object (integrations moved to marketplace packages)', () => {
      expect(Object.keys(INTEGRATION_METADATA)).toHaveLength(0);
    });
  });

  // ==========================================================================
  // getAllIntegrationMetadata Tests
  // ==========================================================================

  describe('getAllIntegrationMetadata', () => {
    it('returns empty array (integrations moved to marketplace packages)', () => {
      const result = getAllIntegrationMetadata();

      expect(Array.isArray(result)).toBe(true);
      expect(result).toHaveLength(0);
    });
  });

  // ==========================================================================
  // getIntegrationMetadata Tests
  // ==========================================================================

  describe('getIntegrationMetadata', () => {
    it('returns undefined for any integration (all moved to marketplace packages)', () => {
      expect(getIntegrationMetadata('mailchimp')).toBeUndefined();
      expect(getIntegrationMetadata('unknown')).toBeUndefined();
    });
  });

  // ==========================================================================
  // getIntegrationService Tests
  // ==========================================================================

  describe('getIntegrationService', () => {
    it('creates dynamic service for any integration slug', async () => {
      vi.mocked(apiRequest).mockResolvedValue({});

      const service = getIntegrationService('custompackage');
      expect(service).toBeDefined();
      expect(typeof service.getStatus).toBe('function');
      expect(typeof service.listConnections).toBe('function');
      expect(typeof service.createConnection).toBe('function');

      await service.getStatus();
      expect(apiRequest).toHaveBeenCalledWith('/integrations/custompackage');
    });
  });
});
