import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock apiClient
vi.mock('../client', () => ({
  default: {
    get: vi.fn(),
    post: vi.fn(),
    patch: vi.fn(),
    delete: vi.fn(),
  },
}));

import {
  getResources,
  getBusinessUsers,
  getBusinessOAuthSettings,
  updateBusinessOAuthSettings,
  getBusinessOAuthCredentials,
  updateBusinessOAuthCredentials,
} from '../business';
import apiClient from '../client';

describe('business API', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('getResources', () => {
    it('fetches all resources from API', async () => {
      const mockResources = [
        {
          id: '1',
          name: 'Resource 1',
          type: 'STAFF',
          maxConcurrentEvents: 1,
        },
        {
          id: '2',
          name: 'Resource 2',
          type: 'EQUIPMENT',
          maxConcurrentEvents: 3,
        },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockResources });

      const result = await getResources();

      expect(apiClient.get).toHaveBeenCalledWith('/resources/');
      expect(result).toEqual(mockResources);
    });

    it('returns empty array when no resources exist', async () => {
      vi.mocked(apiClient.get).mockResolvedValue({ data: [] });

      const result = await getResources();

      expect(result).toEqual([]);
    });
  });

  describe('getBusinessUsers', () => {
    it('fetches all business users from API', async () => {
      const mockUsers = [
        {
          id: '1',
          email: 'owner@example.com',
          name: 'Business Owner',
          role: 'owner',
        },
        {
          id: '2',
          email: 'staff@example.com',
          name: 'Staff Member',
          role: 'staff',
        },
      ];
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockUsers });

      const result = await getBusinessUsers();

      expect(apiClient.get).toHaveBeenCalledWith('/business/users/');
      expect(result).toEqual(mockUsers);
    });

    it('returns empty array when no users exist', async () => {
      vi.mocked(apiClient.get).mockResolvedValue({ data: [] });

      const result = await getBusinessUsers();

      expect(result).toEqual([]);
    });
  });

  describe('getBusinessOAuthSettings', () => {
    it('fetches OAuth settings and transforms snake_case to camelCase', async () => {
      const mockBackendResponse = {
        settings: {
          enabled_providers: ['google', 'microsoft'],
          allow_registration: true,
          auto_link_by_email: false,
          use_custom_credentials: true,
        },
        available_providers: [
          {
            id: 'google',
            name: 'Google',
            icon: 'google-icon',
            description: 'Sign in with Google',
          },
          {
            id: 'microsoft',
            name: 'Microsoft',
            icon: 'microsoft-icon',
            description: 'Sign in with Microsoft',
          },
        ],
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBackendResponse });

      const result = await getBusinessOAuthSettings();

      expect(apiClient.get).toHaveBeenCalledWith('/business/oauth-settings/');
      expect(result).toEqual({
        settings: {
          enabledProviders: ['google', 'microsoft'],
          allowRegistration: true,
          autoLinkByEmail: false,
          useCustomCredentials: true,
        },
        availableProviders: [
          {
            id: 'google',
            name: 'Google',
            icon: 'google-icon',
            description: 'Sign in with Google',
          },
          {
            id: 'microsoft',
            name: 'Microsoft',
            icon: 'microsoft-icon',
            description: 'Sign in with Microsoft',
          },
        ],
      });
    });

    it('handles empty enabled providers array', async () => {
      const mockBackendResponse = {
        settings: {
          enabled_providers: [],
          allow_registration: false,
          auto_link_by_email: false,
          use_custom_credentials: false,
        },
        available_providers: [],
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBackendResponse });

      const result = await getBusinessOAuthSettings();

      expect(result.settings.enabledProviders).toEqual([]);
      expect(result.availableProviders).toEqual([]);
    });

    it('handles undefined enabled_providers by using empty array', async () => {
      const mockBackendResponse = {
        settings: {
          allow_registration: true,
          auto_link_by_email: true,
          use_custom_credentials: false,
        },
        available_providers: [
          {
            id: 'google',
            name: 'Google',
            icon: 'google-icon',
            description: 'Google OAuth',
          },
        ],
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBackendResponse });

      const result = await getBusinessOAuthSettings();

      expect(result.settings.enabledProviders).toEqual([]);
    });

    it('handles undefined available_providers by using empty array', async () => {
      const mockBackendResponse = {
        settings: {
          enabled_providers: ['google'],
          allow_registration: true,
          auto_link_by_email: true,
          use_custom_credentials: false,
        },
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBackendResponse });

      const result = await getBusinessOAuthSettings();

      expect(result.availableProviders).toEqual([]);
    });
  });

  describe('updateBusinessOAuthSettings', () => {
    it('updates OAuth settings and transforms camelCase to snake_case', async () => {
      const frontendSettings = {
        enabledProviders: ['google', 'microsoft'],
        allowRegistration: true,
        autoLinkByEmail: false,
        useCustomCredentials: true,
      };

      const mockBackendResponse = {
        settings: {
          enabled_providers: ['google', 'microsoft'],
          allow_registration: true,
          auto_link_by_email: false,
          use_custom_credentials: true,
        },
        available_providers: [
          {
            id: 'google',
            name: 'Google',
            icon: 'google-icon',
            description: 'Google OAuth',
          },
        ],
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      const result = await updateBusinessOAuthSettings(frontendSettings);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-settings/', {
        enabled_providers: ['google', 'microsoft'],
        allow_registration: true,
        auto_link_by_email: false,
        use_custom_credentials: true,
      });
      expect(result).toEqual({
        settings: {
          enabledProviders: ['google', 'microsoft'],
          allowRegistration: true,
          autoLinkByEmail: false,
          useCustomCredentials: true,
        },
        availableProviders: [
          {
            id: 'google',
            name: 'Google',
            icon: 'google-icon',
            description: 'Google OAuth',
          },
        ],
      });
    });

    it('sends only provided fields to backend', async () => {
      const partialSettings = {
        enabledProviders: ['google'],
      };

      const mockBackendResponse = {
        settings: {
          enabled_providers: ['google'],
          allow_registration: true,
          auto_link_by_email: false,
          use_custom_credentials: false,
        },
        available_providers: [],
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthSettings(partialSettings);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-settings/', {
        enabled_providers: ['google'],
      });
    });

    it('handles updating only allowRegistration', async () => {
      const partialSettings = {
        allowRegistration: false,
      };

      const mockBackendResponse = {
        settings: {
          enabled_providers: [],
          allow_registration: false,
          auto_link_by_email: true,
          use_custom_credentials: false,
        },
        available_providers: [],
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthSettings(partialSettings);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-settings/', {
        allow_registration: false,
      });
    });

    it('handles updating only autoLinkByEmail', async () => {
      const partialSettings = {
        autoLinkByEmail: true,
      };

      const mockBackendResponse = {
        settings: {
          enabled_providers: [],
          allow_registration: false,
          auto_link_by_email: true,
          use_custom_credentials: false,
        },
        available_providers: [],
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthSettings(partialSettings);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-settings/', {
        auto_link_by_email: true,
      });
    });

    it('handles updating only useCustomCredentials', async () => {
      const partialSettings = {
        useCustomCredentials: true,
      };

      const mockBackendResponse = {
        settings: {
          enabled_providers: [],
          allow_registration: false,
          auto_link_by_email: false,
          use_custom_credentials: true,
        },
        available_providers: [],
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthSettings(partialSettings);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-settings/', {
        use_custom_credentials: true,
      });
    });

    it('handles boolean false values correctly', async () => {
      const settings = {
        allowRegistration: false,
        autoLinkByEmail: false,
        useCustomCredentials: false,
      };

      const mockBackendResponse = {
        settings: {
          enabled_providers: [],
          allow_registration: false,
          auto_link_by_email: false,
          use_custom_credentials: false,
        },
        available_providers: [],
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthSettings(settings);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-settings/', {
        allow_registration: false,
        auto_link_by_email: false,
        use_custom_credentials: false,
      });
    });

    it('does not send undefined fields', async () => {
      const settings = {};

      const mockBackendResponse = {
        settings: {
          enabled_providers: [],
          allow_registration: true,
          auto_link_by_email: true,
          use_custom_credentials: false,
        },
        available_providers: [],
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthSettings(settings);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-settings/', {});
    });
  });

  describe('getBusinessOAuthCredentials', () => {
    it('fetches OAuth credentials from API', async () => {
      const mockBackendResponse = {
        credentials: {
          google: {
            client_id: 'google-client-id',
            client_secret: 'google-secret',
            has_secret: true,
          },
          microsoft: {
            client_id: 'microsoft-client-id',
            client_secret: '',
            has_secret: false,
          },
        },
        use_custom_credentials: true,
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBackendResponse });

      const result = await getBusinessOAuthCredentials();

      expect(apiClient.get).toHaveBeenCalledWith('/business/oauth-credentials/');
      expect(result).toEqual({
        credentials: {
          google: {
            client_id: 'google-client-id',
            client_secret: 'google-secret',
            has_secret: true,
          },
          microsoft: {
            client_id: 'microsoft-client-id',
            client_secret: '',
            has_secret: false,
          },
        },
        useCustomCredentials: true,
      });
    });

    it('handles empty credentials object', async () => {
      const mockBackendResponse = {
        credentials: {},
        use_custom_credentials: false,
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBackendResponse });

      const result = await getBusinessOAuthCredentials();

      expect(result.credentials).toEqual({});
      expect(result.useCustomCredentials).toBe(false);
    });

    it('handles undefined credentials by using empty object', async () => {
      const mockBackendResponse = {
        use_custom_credentials: false,
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockBackendResponse });

      const result = await getBusinessOAuthCredentials();

      expect(result.credentials).toEqual({});
    });
  });

  describe('updateBusinessOAuthCredentials', () => {
    it('updates OAuth credentials', async () => {
      const credentials = {
        credentials: {
          google: {
            client_id: 'new-google-client-id',
            client_secret: 'new-google-secret',
          },
        },
        useCustomCredentials: true,
      };

      const mockBackendResponse = {
        credentials: {
          google: {
            client_id: 'new-google-client-id',
            client_secret: 'new-google-secret',
            has_secret: true,
          },
        },
        use_custom_credentials: true,
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      const result = await updateBusinessOAuthCredentials(credentials);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-credentials/', {
        credentials: {
          google: {
            client_id: 'new-google-client-id',
            client_secret: 'new-google-secret',
          },
        },
        use_custom_credentials: true,
      });
      expect(result).toEqual({
        credentials: {
          google: {
            client_id: 'new-google-client-id',
            client_secret: 'new-google-secret',
            has_secret: true,
          },
        },
        useCustomCredentials: true,
      });
    });

    it('updates only credentials without useCustomCredentials', async () => {
      const data = {
        credentials: {
          microsoft: {
            client_id: 'microsoft-id',
          },
        },
      };

      const mockBackendResponse = {
        credentials: {
          microsoft: {
            client_id: 'microsoft-id',
            client_secret: '',
            has_secret: false,
          },
        },
        use_custom_credentials: false,
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthCredentials(data);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-credentials/', {
        credentials: {
          microsoft: {
            client_id: 'microsoft-id',
          },
        },
      });
    });

    it('updates only useCustomCredentials without credentials', async () => {
      const data = {
        useCustomCredentials: false,
      };

      const mockBackendResponse = {
        credentials: {},
        use_custom_credentials: false,
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthCredentials(data);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-credentials/', {
        use_custom_credentials: false,
      });
    });

    it('handles partial credential updates', async () => {
      const data = {
        credentials: {
          google: {
            client_id: 'updated-id',
          },
          microsoft: {
            client_secret: 'updated-secret',
          },
        },
      };

      const mockBackendResponse = {
        credentials: {
          google: {
            client_id: 'updated-id',
            client_secret: 'existing-secret',
            has_secret: true,
          },
          microsoft: {
            client_id: 'existing-id',
            client_secret: 'updated-secret',
            has_secret: true,
          },
        },
        use_custom_credentials: true,
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      const result = await updateBusinessOAuthCredentials(data);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-credentials/', {
        credentials: {
          google: {
            client_id: 'updated-id',
          },
          microsoft: {
            client_secret: 'updated-secret',
          },
        },
      });
      expect(result.credentials.google.client_id).toBe('updated-id');
      expect(result.credentials.microsoft.client_secret).toBe('updated-secret');
    });

    it('handles empty data object', async () => {
      const data = {};

      const mockBackendResponse = {
        credentials: {},
        use_custom_credentials: false,
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      await updateBusinessOAuthCredentials(data);

      expect(apiClient.patch).toHaveBeenCalledWith('/business/oauth-credentials/', {});
    });

    it('handles undefined credentials in response by using empty object', async () => {
      const data = {
        useCustomCredentials: true,
      };

      const mockBackendResponse = {
        use_custom_credentials: true,
      };
      vi.mocked(apiClient.patch).mockResolvedValue({ data: mockBackendResponse });

      const result = await updateBusinessOAuthCredentials(data);

      expect(result.credentials).toEqual({});
    });
  });
});
