// This program has been developed by students from the bachelor Computer Science at Utrecht
// University within the Software Project course.
// © Copyright Utrecht University (Department of Information and Computing Sciences)
import { describe, it, expect} from '@jest/globals';
import {
  type EditorWarning, warningSummary
} from "../../../../../src/pages/VisProgPage/visualProgrammingUI/components/EditorWarnings.tsx";
import useFlowStore from "../../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx";


function makeWarning(
  overrides?: Partial<EditorWarning>
): EditorWarning {
  return {
    scope: { id: 'node-1' },
    type: 'MISSING_INPUT',
    severity: 'ERROR',
    description: 'Missing input',
    ...overrides,
  };
}

describe("editorWarnings", () => {
  describe('registerWarning', () => {
    it('registers a node-level warning', () => {
      const warning = makeWarning();
      const {registerWarning, getWarnings} = useFlowStore.getState()
      registerWarning(warning);

      const warnings = getWarnings();
      expect(warnings).toHaveLength(1);
      expect(warnings[0]).toEqual(warning);
    });

    it('registers a handle-level warning with scoped key', () => {
      const warning = makeWarning({
        scope: { id: 'node-1', handleId: 'input-1' },
      });
      const {registerWarning} = useFlowStore.getState()
      registerWarning(warning);
      const nodeWarnings = useFlowStore.getState().editorWarningRegistry.get('node-1');
      expect(nodeWarnings?.has('MISSING_INPUT:input-1') === true).toBe(true);
    });

    it('updates severityIndex correctly', () => {
      const {registerWarning, severityIndex} = useFlowStore.getState()
      registerWarning(makeWarning());
      expect(severityIndex.get('ERROR')!.size).toBe(1);
    });
  });

  describe('getWarningsBySeverity', () => {
    it('returns only warnings of requested severity', () => {
      const {registerWarning, getWarningsBySeverity} = useFlowStore.getState()
      registerWarning(
        makeWarning({ severity: 'ERROR' })
      );

      registerWarning(
        makeWarning({
          severity: 'WARNING',
          type: 'MISSING_OUTPUT',
        })
      );

      const errors = getWarningsBySeverity('ERROR');
      const warnings = getWarningsBySeverity('WARNING');

      expect(errors).toHaveLength(1);
      expect(warnings).toHaveLength(1);
    });
  });

  describe('isProgramValid', () => {
    it('returns true when no ERROR warnings exist', () => {
      expect(useFlowStore.getState().isProgramValid()).toBe(true);
    });

    it('returns false when ERROR warnings exist', () => {
      const {registerWarning, isProgramValid} = useFlowStore.getState()
      registerWarning(makeWarning());
      expect(isProgramValid()).toBe(false);
    });
  });

  describe('unregisterWarning', () => {
    it('removes warning from registry and severityIndex', () => {
      const warning = makeWarning();
      const {
        registerWarning,
        getWarnings,
        unregisterWarning,
        severityIndex
      } = useFlowStore.getState()

      registerWarning(warning);

      unregisterWarning('node-1', 'MISSING_INPUT');

      expect(getWarnings()).toHaveLength(0);
      expect(severityIndex.get('ERROR')!.size).toBe(0);
    });

    it('does nothing if warning does not exist', () => {
      expect(() =>
        useFlowStore.getState().unregisterWarning('node-1', 'DOES_NOT_EXIST')
      ).not.toThrow();
    });
  });

  describe('unregisterWarningsForId', () => {
    it('removes all warnings for a node', () => {
      const {registerWarning, unregisterWarningsForId, getWarnings, severityIndex} = useFlowStore.getState()
      registerWarning(
        makeWarning({
          scope: { id: 'node-1', handleId: 'h1' },
        })
      );

      registerWarning(
        makeWarning({
          scope: { id: 'node-1' },
          type: 'MISSING_OUTPUT',
          severity: 'WARNING',
        })
      );

      unregisterWarningsForId('node-1');

      expect(getWarnings()).toHaveLength(0);
      expect(
        severityIndex.get('ERROR')!.size
      ).toBe(0);
      expect(
        severityIndex.get('WARNING')!.size
      ).toBe(0);
    });
  });

  describe('warningSummary', () => {
    it('returns correct counts and validity', () => {
      const {registerWarning} = useFlowStore.getState()
      registerWarning(
        makeWarning({ severity: 'ERROR' })
      );

      const summary = warningSummary();

      expect(summary.error).toBe(1);
      expect(summary.warning).toBe(0);
      expect(summary.info).toBe(0);
      expect(summary.isValid).toBe(false);
    });
  });
})
