import { ApplicationProcess } from '@core/application';
import { Spectator, createComponentFactory } from '@ngneat/spectator';
import { UiIconModule } from '@ui/icon';
import { UiModalService } from '@ui/modal';
import { ShellProcessTabComponent } from './process-tab.component';

describe('ShellProcessTabComponent', () => {
  const process: ApplicationProcess = {
    id: 1,
    name: 'Vorgang',
    type: 'cart',
    section: 'customer',
  };

  let spectator: Spectator<ShellProcessTabComponent>;

  const createComponent = createComponentFactory({
    component: ShellProcessTabComponent,
    declarations: [],
    imports: [UiIconModule],
    mocks: [UiModalService],
  });

  beforeEach(() => (spectator = createComponent({ props: { process } })));

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

  describe('input process', () => {
    it('should render h2 with process name', () => {
      expect(spectator.query('h2')).toHaveText(`${process.name}`);
    });

    describe('process.type is cart', () => {
      it('should render button.badge', () => {
        expect(spectator.query('button.badge')).toBeVisible();
      });

      it('should render ui-icon with icon cart', () => {
        expect(spectator.query('button.badge ui-icon')).toHaveAttribute('icon', 'cart');
      });

      it('should render process.data.count as text', () => {
        spectator.setInput('process', { ...process, data: { count: 5 } });
        expect(spectator.query('button.badge span')).toHaveText('5');
      });

      it('should render 0 if process.data.count is not set', () => {
        expect(spectator.query('button.badge span')).toHaveText('0');
      });
    });
  });

  describe('input isActive', () => {
    it('should render the close button if isActive is true for the current active process and the process is closable', () => {
      spectator.setInput('isActive', true);
      spectator.setInput('process', { id: 1, name: 'Vorgang', closeable: true, section: 'customer' });
      expect(spectator.query('button.close')).toBeVisible();
    });

    it('should add class .active for process button if isActive is true for the current active process and the process is closable', () => {
      spectator.setInput('isActive', true);
      spectator.setInput('process', { id: 1, name: 'Vorgang', closeable: true, section: 'customer' });
      expect(spectator.query('button.tab')).toHaveClass('active');
    });

    it('should not render the close button if isActive is false for all inactive processes', () => {
      spectator.setInput('isActive', false);
      expect(spectator.query('button.close')).not.toBeVisible();
    });

    it('should not add class .active for process button if isActive is false for all inactive tabs', () => {
      spectator.setInput('isActive', false);
      expect(spectator.query('button.tab')).not.toHaveClass('active');
    });
  });

  describe('output activateProcess', () => {
    it('should emit after clicking on process tab', () => {
      spyOn(spectator.component.activateProcess, 'emit');
      spectator.click('button.tab');
      expect(spectator.component.activateProcess.emit).toHaveBeenCalled();
    });
  });

  describe('output processAction', () => {
    it('should emit after clicking on button.badge', () => {
      spyOn(spectator.component.processAction, 'emit');
      spectator.click('button.badge');
      expect(spectator.component.processAction.emit).toHaveBeenCalled();
    });
  });

  describe('output closeProcess', () => {
    it('should emit with process.id after clicking on button.close on active processes', () => {
      spectator.setInput('isActive', true);
      spectator.setInput('process', { id: 1, name: 'Vorgang', closeable: true, section: 'customer' });
      spyOn(spectator.component.closeProcess, 'emit');
      spectator.click('button.close');
      expect(spectator.component.closeProcess.emit).toHaveBeenCalledWith(process.id);
    });
  });

  describe('onTabClick()', () => {
    it('should be called on button.tab click', () => {
      spyOn(spectator.component, 'onTabClick');
      spectator.click('button.tab');
      expect(spectator.component.onTabClick).toHaveBeenCalled();
    });

    it('should emit activateProcess with the process.id', () => {
      spyOn(spectator.component.activateProcess, 'emit');
      spectator.component.onTabClick();
      expect(spectator.component.activateProcess.emit).toHaveBeenCalled();
    });

    it('should call scrollIntoView on the tab ViewChild', () => {
      spyOn(spectator.component.tab.nativeElement, 'scrollIntoView');
      spectator.component.onTabClick();
      expect(spectator.component.tab.nativeElement.scrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth' });
    });
  });

  describe('triggerAnimation()', () => {
    it('should set animate to true', () => {
      spectator.component.animate = false;
      spectator.component.triggerAnimation();
      expect(spectator.component.animate).toBeTrue();
    });
  });

  describe('slideAnimationDone()', () => {
    it('should be called when slideIne.done event is triggered', () => {
      spyOn(spectator.component, 'slideAnimationDone');
      spectator.triggerEventHandler('button.tab', '@slideIn.done', undefined);
      expect(spectator.component.slideAnimationDone).toHaveBeenCalled();
    });

    it('should call scrollIntoView when the isActive is true', () => {
      spectator.setInput('isActive', true);
      spyOn(spectator.component.tab.nativeElement, 'scrollIntoView');
      spectator.component.slideAnimationDone(undefined);
      expect(spectator.component.tab.nativeElement.scrollIntoView).toHaveBeenCalledWith({ behavior: 'smooth' });
    });

    it('should not call scrollIntoView when the isActive is false', () => {
      spectator.setInput('isActive', false);
      spyOn(spectator.component.tab.nativeElement, 'scrollIntoView');
      spectator.component.slideAnimationDone(undefined);
      expect(spectator.component.tab.nativeElement.scrollIntoView).not.toHaveBeenCalled();
    });

    it('should set animate to false', () => {
      spectator.component.animate = true;
      spectator.component.slideAnimationDone(undefined);
      expect(spectator.component.animate).toBeFalse();
    });
  });
});
