/*
 * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch den
 * Ministerpräsidenten des Landes Schleswig-Holstein
 * Staatskanzlei
 * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
 *
 * Lizenziert unter der EUPL, Version 1.2 oder - sobald
 * diese von der Europäischen Kommission genehmigt wurden -
 * Folgeversionen der EUPL ("Lizenz");
 * Sie dürfen dieses Werk ausschließlich gemäß
 * dieser Lizenz nutzen.
 * Eine Kopie der Lizenz finden Sie hier:
 *
 * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
 *
 * Sofern nicht durch anwendbare Rechtsvorschriften
 * gefordert oder in schriftlicher Form vereinbart, wird
 * die unter der Lizenz verbreitete Software "so wie sie
 * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
 * ausdrücklich oder stillschweigend - verbreitet.
 * Die sprachspezifischen Genehmigungen und Beschränkungen
 * unter der Lizenz sind dem Lizenztext zu entnehmen.
 */
import {
  ApiError,
  EMPTY_STRING,
  MessageCode,
  createEmptyStateResource,
  createErrorStateResource,
  createStateResource,
} from '@alfa-client/tech-shared';
import { getElementFromFixture } from '@alfa-client/test-utils';
import { SpinnerComponent } from '@alfa-client/ui';
import { NO_NAME_MESSAGE, UserProfileResource, userProfileMessage } from '@alfa-client/user-profile-shared';
import { SimpleChange } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatIcon } from '@angular/material/icon';
import { faker } from '@faker-js/faker';
import { ErrorIconComponent, UserIconComponent as OdsUserIconComponent, TooltipDirective } from '@ods/system';
import { getDataTestClassOf } from 'libs/tech-shared/test/data-test';
import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile';
import { MockComponent, MockDirective } from 'ng-mocks';
import { createApiError, createIssue } from '../../../../tech-shared/test/error';
import { UserIconComponent } from './user-icon.component';

describe('UserIconComponent', () => {
  let component: UserIconComponent;
  let fixture: ComponentFixture<UserIconComponent>;

  const profileAssignedIcon: string = getDataTestClassOf('user-profile-assigned');
  const profileUnassigned: string = getDataTestClassOf('user-profile-unassigned');
  const profileUserNotFound: string = getDataTestClassOf('user-profile-user-not-found');
  const profileServiceUnavailable: string = getDataTestClassOf('user-profile-service-unavailable');

  const userProfile: UserProfileResource = createUserProfileResource();

  beforeEach(async () => {
    TestBed.configureTestingModule({
      declarations: [
        UserIconComponent,
        MatIcon,
        MockComponent(SpinnerComponent),
        MockDirective(TooltipDirective),
        MockComponent(ErrorIconComponent),
        MockComponent(OdsUserIconComponent),
      ],
    });
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(UserIconComponent);
    component = fixture.componentInstance;
    component.userProfileStateResource = createStateResource(userProfile);
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  describe('on icon place', () => {
    it('should show icon unassigned', () => {
      component.userProfileStateResource = createEmptyStateResource();

      fixture.detectChanges();
      const element = getElementFromFixture(fixture, profileUnassigned);

      expect(element).toBeInstanceOf(HTMLElement);
    });

    it('should show icon assigned', () => {
      component.userProfileStateResource = createStateResource(userProfile);

      fixture.detectChanges();
      const element = getElementFromFixture(fixture, profileAssignedIcon);

      expect(element).toBeInstanceOf(HTMLElement);
    });

    it('should show user not found icon', () => {
      component.userProfileStateResource = createErrorStateResource(
        createApiErrorWithMessageCode(MessageCode.RESOURCE_NOT_FOUND),
      );

      fixture.detectChanges();
      const element = getElementFromFixture(fixture, profileUserNotFound);

      expect(element).toBeInstanceOf(HTMLElement);
    });

    it('should show service unavailable icon', () => {
      component.userProfileStateResource = createErrorStateResource(
        createApiErrorWithMessageCode(MessageCode.SERVICE_UNAVAILABLE),
      );

      fixture.detectChanges();
      const element = getElementFromFixture(fixture, profileServiceUnavailable);

      expect(element).toBeInstanceOf(HTMLElement);
    });
  });

  describe('ngOnChanges', () => {
    const userProfileChange: SimpleChange = new SimpleChange(1, 2, true);

    it('should get tooltip', () => {
      component.getTooltip = jest.fn();

      component.ngOnChanges({ userProfileStateResource: userProfileChange });

      expect(component.getTooltip).toHaveBeenCalled();
    });

    it('should not get tooltip', () => {
      component.getTooltip = jest.fn();
      component.withTooltip = false;

      component.ngOnChanges({ userProfileStateResource: userProfileChange });

      expect(component.getTooltip).not.toHaveBeenCalled();
    });
  });

  describe('tooltip', () => {
    it('should return user name', () => {
      component.userProfileStateResource = createStateResource(userProfile);

      const tooltip = component.getTooltip();

      expect(tooltip).toEqual(userProfile.firstName + ' ' + userProfile.lastName);
    });

    it('should return no user assigned', () => {
      component.userProfileStateResource = createEmptyStateResource();

      const tooltip = component.getTooltip();

      expect(tooltip).toEqual(userProfileMessage.UNASSIGNED);
    });

    it('should return apiError as stateResource', () => {
      component.userProfileStateResource = createErrorStateResource(createApiError());
      component.getErrorTooltip = jest.fn();

      component.getTooltip();

      expect(component.getErrorTooltip).toHaveBeenCalled();
    });

    it('should return empty string on missing name', () => {
      component.userProfileStateResource = createStateResource({
        ...userProfile,
        firstName: EMPTY_STRING,
        lastName: EMPTY_STRING,
      });

      const tooltip = component.getTooltip();

      expect(tooltip).toEqual(NO_NAME_MESSAGE);
    });
  });

  describe('error tooltip', () => {
    it('should return user not found', () => {
      component.userProfileStateResource = createErrorStateResource(
        createApiErrorWithMessageCode(MessageCode.RESOURCE_NOT_FOUND),
      );

      const tooltip = component.getErrorTooltip();

      expect(tooltip).toEqual(userProfileMessage[MessageCode.RESOURCE_NOT_FOUND]);
    });

    it('should return backend service unavailable', () => {
      component.userProfileStateResource = createErrorStateResource(
        createApiErrorWithMessageCode(MessageCode.SERVICE_UNAVAILABLE),
      );

      const tooltip = component.getErrorTooltip();

      expect(tooltip).toEqual(userProfileMessage[MessageCode.SERVICE_UNAVAILABLE]);
    });

    describe('on unexpected error', () => {
      it('should return empty string on non existing messageCode issue', () => {
        component.userProfileStateResource = createErrorStateResource(createApiErrorWithMessageCode(faker.word.sample()));

        const tooltip = component.getErrorTooltip();

        expect(tooltip).toEqual(userProfileMessage.UNKNOW_ERROR);
      });

      it('should return empty string on null issue', () => {
        component.userProfileStateResource = createErrorStateResource({
          ...createApiError(),
          issues: [null],
        });

        const tooltip = component.getErrorTooltip();

        expect(tooltip).toEqual(userProfileMessage.UNKNOW_ERROR);
      });
    });
  });

  function createApiErrorWithMessageCode(messageCode: string): ApiError {
    return { ...createApiError(), issues: [{ ...createIssue(), messageCode }] };
  }
});