/*
 * Copyright (C) 2020 Robert Bosch GmbH Copyright (C) 2020 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { CircularGaugeComponent } from './circular-gauge.component';

describe('CircularGaugeComponent ', () => {
  let component: CircularGaugeComponent;

  beforeEach(() => {
    component = new CircularGaugeComponent();
    component.minValue = -10;
    component.maxValue = 120;
    component.ngOnInit();
  });

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

  it('should return no initial value', () => {
    expect(component.currentValue).toBeUndefined();
  });

  it('should set an arc path for the gauge', () => {
    expect(component.gaugeArcPath).not.toBeUndefined();
  });

  it('should return the value that has been set', () => {
    component.currentValue = 53.2;
    expect(component.currentValue).toEqual(53.2);
  });

  describe('value to percentage calculation', () => {
    it('range 0 to 100', () => {
      component.minValue = 0;
      component.maxValue = 100;
      expect(component.valueToPercentage(0.0)).toEqual(0.0);
      expect(component.valueToPercentage(50.0)).toEqual(50.0);
      expect(component.valueToPercentage(100.0)).toEqual(100.0);
    });

    it('range 10 to 20', () => {
      component.minValue = 10;
      component.maxValue = 20;
      expect(component.valueToPercentage(10.0)).toEqual(0.0);
      expect(component.valueToPercentage(15.0)).toEqual(50.0);
      expect(component.valueToPercentage(20.0)).toEqual(100.0);
    });

    it('range -10 to 10', () => {
      component.minValue = -10;
      component.maxValue = 10;
      expect(component.valueToPercentage(-10.0)).toEqual(0.0);
      expect(component.valueToPercentage(0.0)).toEqual(50.0);
      expect(component.valueToPercentage(10.0)).toEqual(100.0);
    });

    it('range -3 to -1', () => {
      component.minValue = -3;
      component.maxValue = -1;
      expect(component.valueToPercentage(-3.0)).toEqual(0.0);
      expect(component.valueToPercentage(-2.0)).toEqual(50.0);
      expect(component.valueToPercentage(-1.0)).toEqual(100.0);
    });

    it('limits angle if value exeeds minimum', () => {
      component.minValue = 0;
      component.maxValue = 100;
      expect(component.valueToPercentage(-0.5)).toEqual(0.0);
    });

    it('limits angle if value exeeds maximum', () => {
      component.minValue = 0;
      component.maxValue = 100;
      expect(component.valueToPercentage(100.3)).toEqual(100.0);
    });
  });

  describe('value to angle calculation', () => {
    test.each([undefined, null, 0, NaN])('should return 0° for %s', (value) => {
      component.minValue = -4;
      component.maxValue = 27;

      const angle = component.valueToAngle(value);

      expect(angle).toBe(0);
    });
  });

  describe('Gauge state', () => {
    it('should be unknown when no thresholds set', () => {
      component.currentValue = 34;
      expect(component.gaugeState).toEqual('unknown');
    });

    describe('both thresholds are set', () => {
      beforeEach(() => {
        component.warnThreshold = 91;
        component.errorThreshold = 85;
      });

      it('should be ok when value is above all thresholds', () => {
        component.currentValue = 92;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be ok when value is equal to warn thresholds', () => {
        component.currentValue = 91;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be warn when value is below warn thresholds', () => {
        component.currentValue = 90.9;
        expect(component.gaugeState).toEqual('warn');
      });

      it('should be warn when value is equal to error thresholds', () => {
        component.currentValue = 85;
        expect(component.gaugeState).toEqual('warn');
      });

      it('should be error when value is below error thresholds', () => {
        component.currentValue = 84.9;
        expect(component.gaugeState).toEqual('error');
      });
    });

    describe('error threshold is set', () => {
      beforeEach(() => {
        component.errorThreshold = 85;
      });

      it('should be ok when value is above all thresholds', () => {
        component.currentValue = 92;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be ok when value is equal to error thresholds', () => {
        component.currentValue = 85;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be error when value is below error thresholds', () => {
        component.currentValue = 84.9;
        expect(component.gaugeState).toEqual('error');
      });
    });

    describe('warn threshold is set', () => {
      beforeEach(() => {
        component.warnThreshold = 85;
      });

      it('should be ok when value is above all thresholds', () => {
        component.currentValue = 92;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be ok when value is equal to warn thresholds', () => {
        component.currentValue = 85;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be warn when value is below warn thresholds', () => {
        component.currentValue = 84.9;
        expect(component.gaugeState).toEqual('warn');
      });
    });
  });

  describe('Gauge state inverted', () => {
    beforeEach(() => {
      component.invertThresholds = true;
    });

    it('should be unknown when no thresholds set', () => {
      component.currentValue = 34;
      expect(component.gaugeState).toEqual('unknown');
    });

    describe('both thresholds are set', () => {
      beforeEach(() => {
        component.warnThreshold = 85;
        component.errorThreshold = 92;
      });

      it('should be ok when value is below all thresholds', () => {
        component.currentValue = 84.9;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be ok when value is equal to warn thresholds', () => {
        component.currentValue = 85;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be warn when value is above warn thresholds', () => {
        component.currentValue = 85.1;
        expect(component.gaugeState).toEqual('warn');
      });

      it('should be warn when value is equal to error thresholds', () => {
        component.currentValue = 92;
        expect(component.gaugeState).toEqual('warn');
      });

      it('should be error when value is below error thresholds', () => {
        component.currentValue = 92.1;
        expect(component.gaugeState).toEqual('error');
      });
    });

    describe('error threshold is set', () => {
      beforeEach(() => {
        component.errorThreshold = 85;
      });

      it('should be ok when value is below all thresholds', () => {
        component.currentValue = 84.9;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be ok when value is equal to error thresholds', () => {
        component.currentValue = 85;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be error when value is below error thresholds', () => {
        component.currentValue = 85.1;
        expect(component.gaugeState).toEqual('error');
      });
    });

    describe('warn threshold is set', () => {
      beforeEach(() => {
        component.warnThreshold = 85;
      });

      it('should be ok when value is below all thresholds', () => {
        component.currentValue = 84.9;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be ok when value is equal to warn thresholds', () => {
        component.currentValue = 85;
        expect(component.gaugeState).toEqual('ok');
      });

      it('should be warn when value is below warn thresholds', () => {
        component.currentValue = 85.1;
        expect(component.gaugeState).toEqual('warn');
      });
    });
  });

  describe('Threshold indicator visbility', () => {
    describe('Normal threshold behavior', () => {
      beforeEach(() => {
        component.warnThreshold = 92;
        component.errorThreshold = 85;
      });

      it('should not invert both indicators when value is below both thresholds', () => {
        component.currentValue = 84;
        expect(component.warnThresholdIndicatorInverted).toEqual(false);
        expect(component.errorThresholdIndicatorInverted).toEqual(false);
      });

      it('should invert only error when value is between both thresholds', () => {
        component.currentValue = 85.1;
        expect(component.warnThresholdIndicatorInverted).toEqual(false);
        expect(component.errorThresholdIndicatorInverted).toEqual(true);
      });

      it('should invert both indicators when value is above warn thresholds', () => {
        component.currentValue = 92.1;
        expect(component.warnThresholdIndicatorInverted).toEqual(true);
        expect(component.errorThresholdIndicatorInverted).toEqual(true);
      });
    });

    describe('Inverted threshold behavior', () => {
      beforeEach(() => {
        component.invertThresholds = true;
        component.warnThreshold = 85;
        component.errorThreshold = 92;
      });

      it('should not invert both indicators when value is below both thresholds', () => {
        component.currentValue = 84;
        expect(component.warnThresholdIndicatorInverted).toEqual(false);
        expect(component.errorThresholdIndicatorInverted).toEqual(false);
      });

      it('should invert only warn when value is between both thresholds', () => {
        component.currentValue = 85.1;
        expect(component.warnThresholdIndicatorInverted).toEqual(true);
        expect(component.errorThresholdIndicatorInverted).toEqual(false);
      });

      it('should invert both indicators when value is above warn thresholds', () => {
        component.currentValue = 92.1;
        expect(component.warnThresholdIndicatorInverted).toEqual(true);
        expect(component.errorThresholdIndicatorInverted).toEqual(true);
      });
    });
  });
});
