import * as React from 'react';
import { UserDecision, UI_LAYER } from '@usercentrics/cmp-browser-sdk';
import { renderHook, act } from '@testing-library/react-hooks';

import { defaultConsentEventName, UsercentricsProvider, useUsercentrics } from './UsercentricsProvider';

const mockAcceptAll = jest.fn();
const mockDenyAll = jest.fn();

const mockCategory = {
  description: 'Notihng',
  isEssential: false,
  isHidden: false,
  label: 'Planing',
  slug: '0001',
  services: [
    {
      id: 'LykAT-gy',
      consent: { status: false },
    },
  ],
};

class MockUsercentrics {
  categories = [mockCategory];
  getCategoriesFullInfo = () => Promise.resolve(this.categories);
  getSettingsUI = () => ({ foo: 'bar' });
  getSettingsLabels = () => ({ foo: 'bar' });
  init = () => Promise.resolve({ initialLayer: UI_LAYER.FIRST_LAYER });
  acceptAllServices = mockAcceptAll;
  denyAllServices = mockDenyAll;
  updateServices = (userDecisions: UserDecision[]) => {
    this.categories = [
      {
        ...mockCategory,
        services: [
          {
            id: userDecisions[0].serviceId,
            consent: { status: userDecisions[0].status },
          },
        ],
      },
    ];
  };
}

jest.mock('./loadUsercentrics', () => ({
  loadUsercentrics: () => MockUsercentrics,
}));

const Wrapper = ({ children }: { children: React.ReactNode }) => {
  return (
    <UsercentricsProvider loadingUI={() => <></>} settingsId="SETTINGS_ID" abTestValue={{ fakeTest: true } as any}>
      {children}
    </UsercentricsProvider>
  );
};

describe('useUserCentrics', () => {
  it('handles initial state', async () => {
    const { result, waitForNextUpdate } = renderHook(() => useUsercentrics(), {
      wrapper: Wrapper,
    });

    await waitForNextUpdate();

    const { handlers, ...rest } = result.current;

    expect(rest).toEqual({
      abTestValue: { fakeTest: true },
      appearance: 'wall',
      showCloseAndAcceptAllButton: false,
      categories: [mockCategory],
      consentEventName: defaultConsentEventName,
      activeLayer: UI_LAYER.FIRST_LAYER,
      settings: { foo: 'bar' },
      settingsLabels: { foo: 'bar' },
      status: 'initialized',
      locale: 'en',
    });
    expect(handlers).not.toEqual(null);
  });

  it('handles updates', async () => {
    const { result, waitForNextUpdate } = renderHook(() => useUsercentrics(), {
      wrapper: Wrapper,
    });
    await waitForNextUpdate();

    if (result.current.handlers) {
      const { handlers } = result.current;
      act(() => {
        handlers.acceptAll();
      });

      await waitForNextUpdate();
      expect(mockAcceptAll).toHaveBeenCalledTimes(1);

      act(() => {
        handlers.denyAll();
      });

      await waitForNextUpdate();
      expect(mockDenyAll).toHaveBeenCalledTimes(1);

      act(() => {
        handlers.accept([{ status: true, serviceId: 'LykAT-gy' }]);
      });

      await waitForNextUpdate();

      const service = result.current.categories[0].services[0];
      expect(service.id).toEqual('LykAT-gy');
      expect(service.consent.status).toEqual(true);
    }
  });
});
