import { TestBed } from '@angular/core/testing';

import { TreeNode, TreeNodeModel, TreeNodesSelectorService } from './tree-nodes-selector.service';

describe('TreeNodesSelectorService', () => {
  let service: TreeNodesSelectorService;

  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(TreeNodesSelectorService);
  });

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

  describe('allChildLeafNodesAreSelected', () => {
    it('should return false if not all leaf nodes among the given tree nodes direct children are selectd', () => {
      const treeNode: TreeNode = {
        label: 'root',
        isSelected: false,
        value: null,
        children: [
          {
            label: 'level 1',
            isSelected: false,
            value: null,
          },
          {
            label: 'level 1',
            isSelected: true,
            value: null,
          },
        ],
      };
      expect(service.allChildLeafNodesAreSelected(treeNode)).toBe(false);
    });

    it('should return true if all leaf nodes among the given tree nodes direct children are selectd', () => {
      const treeNode = {
        label: 'root',
        isSelected: false,
        value: null,
        children: [
          {
            label: 'level 1',
            isSelected: true,
            value: null,
          },
          {
            label: 'level 1',
            isSelected: true,
            value: null,
          },
        ],
      };

      expect(service.allChildLeafNodesAreSelected(treeNode)).toBe(true);
    });
  });

  describe('getFilteredTreeNodeChildren', () => {
    it('should set the propert hideTreeNode to true for all children with a label that contains the provided text when compared case insensitive, trimming white space and return them.', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        children: [
          {
            label: 'a B',
            isSelected: true,
            value: null,
            uuid: '1',
          },
          {
            label: 'a b c',
            isSelected: false,
            value: null,
            uuid: '2',
          },
          {
            label: 'h b C f',
            isSelected: true,
            value: null,
            uuid: '3',
          },
          {
            label: 'd f',
            isSelected: true,
            value: null,
            uuid: '4',
          },
        ],
      };

      const result = service.getFilteredTreeNodeChildren({ text: 'B C', treeNode });

      expect(result).not.toBeUndefined();
      expect(result).not.toBeNull();
      expect(result.length).toEqual(4);
      expect(result[0].hideTreeNode).toBe(true);
      expect(result[0].uuid).toEqual('1');
      expect(result[1].hideTreeNode).toBe(false);
      expect(result[1].uuid).toEqual('2');
      expect(result[2].hideTreeNode).toBe(false);
      expect(result[2].uuid).toEqual('3');
      expect(result[3].hideTreeNode).toBe(true);
      expect(result[3].uuid).toEqual('4');
    });
  });

  describe('getTreeNodeFilteredBySelectedLeafOrDecsendants', () => {
    it('should return a tree node that either is a selected leaf node or has at least one descendant tree node that is a selected leaf node', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
            uuid: '1',
            children: [
              {
                label: '1evel 2',
                isSelected: true,
                value: null,
                uuid: '1_1',
                children: [
                  {
                    label: '1evel 3',
                    isSelected: false,
                    value: null,
                    uuid: '1_1_1',
                  },
                  {
                    label: 'level 3',
                    isSelected: false,
                    value: null,
                    uuid: '1_1_2',
                  },
                ],
              },
              {
                label: 'level 2',
                isSelected: true,
                value: null,
                uuid: '1_2',
              },
            ],
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            uuid: '2',
            children: [
              {
                label: 'level 2',
                isSelected: false,
                value: null,
                uuid: '2_1',
                children: [
                  {
                    label: '1evel 3',
                    isSelected: false,
                    value: null,
                    uuid: '2_1_1',
                  },
                  {
                    label: 'level 3',
                    isSelected: true,
                    value: null,
                    uuid: '2_1_2',
                  },
                ],
              },
              {
                label: 'level 2',
                isSelected: true,
                value: null,
                uuid: '2_2',
              },
            ],
          },
        ],
      };

      const result: TreeNodeModel = service.getTreeNodeFilteredBySelectedLeafOrDecsendants(treeNode);

      expect(result).not.toBeUndefined();
      expect(result).not.toBeNull();
      expect(result).not.toBeNull();
      expect(result.uuid).toEqual('0');
      expect(result.children).not.toBeUndefined();
      expect(result.children).not.toBeNull();
      expect(result.children.length).toEqual(2);
      expect(result.children[0].uuid).toEqual('1');
      expect(result.children[0].children).not.toBeUndefined();
      expect(result.children[0].children).not.toBeNull();
      expect(result.children[0].children.length).toEqual(1);
      expect(result.children[0].children[0].uuid).toEqual('1_2');
      expect(result.children[1].uuid).toEqual('2');
      expect(result.children[1].children).not.toBeUndefined();
      expect(result.children[1].children).not.toBeNull();
      expect(result.children[1].children.length).toEqual(2);
      expect(result.children[1].children[0].uuid).toEqual('2_1');
      expect(result.children[1].children[0].children).not.toBeUndefined();
      expect(result.children[1].children[0].children).not.toBeNull();
      expect(result.children[1].children[0].children.length).toEqual(1);
      expect(result.children[1].children[0].children[0].uuid).toEqual('2_1_2');
      expect(result.children[1].children[1].uuid).toEqual('2_2');
    });
  });

  describe('getTreeNodeWithAllNodesSelected', () => {
    it('should return a tree node with all sub nodes having the property isSelected set to true', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
            uuid: '1',
            children: [
              {
                label: '1evel 2',
                isSelected: true,
                value: null,
                uuid: '1_1',
              },
              {
                label: 'level 2',
                isSelected: true,
                value: null,
                uuid: '1_2',
              },
            ],
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            uuid: '2',
            children: [
              {
                label: 'level 2',
                isSelected: false,
                value: null,
                uuid: '2_1',
              },
              {
                label: 'level 2',
                isSelected: true,
                value: null,
                uuid: '2_2',
              },
            ],
          },
        ],
      };

      const result: TreeNodeModel = service.getTreeNodeWithAllNodesSelected(treeNode);

      expect(result).not.toBeUndefined();
      expect(result).not.toBeNull();
      expect(result.isSelected).toBe(true);
      expect(result.children[0].isSelected).toBe(true);
      expect(result.children[0].children[0].isSelected).toBe(true);
      expect(result.children[0].children[1].isSelected).toBe(true);
      expect(result.children[1].isSelected).toBe(true);
      expect(result.children[1].children[0].isSelected).toBe(true);
      expect(result.children[1].children[1].isSelected).toBe(true);
    });
  });

  describe('getTreeNodeWithNoNodesSelected', () => {
    it('should return a tree node with all sub nodes having the property isSelected set to false', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
            uuid: '1',
            children: [
              {
                label: '1evel 2',
                isSelected: true,
                value: null,
                uuid: '1_1',
              },
              {
                label: 'level 2',
                isSelected: true,
                value: null,
                uuid: '1_2',
              },
            ],
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            uuid: '2',
            children: [
              {
                label: 'level 2',
                isSelected: false,
                value: null,
                uuid: '2_1',
              },
              {
                label: 'level 2',
                isSelected: true,
                value: null,
                uuid: '2_2',
              },
            ],
          },
        ],
      };

      const result: TreeNodeModel = service.getTreeNodeWithNoNodesSelected(treeNode);

      expect(result).not.toBeUndefined();
      expect(result).not.toBeNull();
      expect(result.isSelected).toBe(false);
      expect(result.children[0].isSelected).toBe(false);
      expect(result.children[0].children[0].isSelected).toBe(false);
      expect(result.children[0].children[1].isSelected).toBe(false);
      expect(result.children[1].isSelected).toBe(false);
      expect(result.children[1].children[0].isSelected).toBe(false);
      expect(result.children[1].children[1].isSelected).toBe(false);
    });
  });

  describe('getVisibleChildren', () => {
    it('should return a list with all the child nodes having property hideTreeNode set to false', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
            uuid: '1',
            hideTreeNode: true,
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            uuid: '2',
            hideTreeNode: false,
          },
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
            uuid: '3',
            hideTreeNode: true,
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            uuid: '4',
            hideTreeNode: false,
          },
        ],
      };

      const result = service.getVisibleChildren(treeNode);

      expect(result).not.toBeUndefined();
      expect(result).not.toBeNull();
      expect(result.length).toEqual(2);
      expect(result[0].uuid).toEqual('2');
      expect(result[1].uuid).toEqual('4');
    });
  });

  describe('hasChildLeafNodes', () => {
    it('should return true when the tree node has a leaf node amongst its children', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            children: [
              {
                label: '1evel 2',
                isSelected: false,
                value: null,
              },
            ],
          },
        ],
      };

      const result = service.hasChildLeafNodes(treeNode);

      expect(result).toBe(true);
    });

    it('should return false when the tree node has no leaf node amongst its children', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
            children: [
              {
                label: '1evel 2',
                isSelected: false,
                value: null,
              },
            ],
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            children: [
              {
                label: '1evel 2',
                isSelected: false,
                value: null,
              },
            ],
          },
        ],
      };

      const result = service.hasChildLeafNodes(treeNode);

      expect(result).toBe(false);
    });
  });

  describe('hasSelectedAllLeafNodes', () => {
    it('should return true when all leaf nodes are selected', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: true,
            value: null,
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            children: [
              {
                label: '1evel 2',
                isSelected: true,
                value: null,
              },
              {
                label: '1evel 2',
                isSelected: false,
                value: null,
                children: [
                  {
                    label: '1evel 3',
                    isSelected: true,
                    value: null,
                  },
                  {
                    label: '1evel 3',
                    isSelected: true,
                    value: null,
                  },
                ],
              },
            ],
          },
        ],
      };

      const result = service.hasChildLeafNodes(treeNode);

      expect(result).toBe(true);
    });

    it('should return false when at least one leaf node is not selected', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
            children: [
              {
                label: '1evel 2',
                isSelected: true,
                value: null,
              },
            ],
          },
          {
            label: 'level 1',
            isSelected: true,
            value: null,
            children: [
              {
                label: '1evel 2',
                isSelected: false,
                value: null,
              },
            ],
          },
        ],
      };

      const result = service.hasSelectedAllLeafNodes(treeNode);

      expect(result).toBe(false);
    });
  });

  describe('hasSelectedLeafNodeDescendant', () => {
    it('should return true when there is at least one selected leaf node descendant.', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            children: [
              {
                label: '1evel 2',
                isSelected: false,
                value: null,
              },
              {
                label: '1evel 2',
                isSelected: false,
                value: null,
                children: [
                  {
                    label: '1evel 3',
                    isSelected: false,
                    value: null,
                  },
                  {
                    label: '1evel 3',
                    isSelected: true,
                    value: null,
                  },
                ],
              },
            ],
          },
        ],
      };

      const result = service.hasSelectedLeafNodeDescendant(treeNode);

      expect(result).toBe(true);
    });

    it('should return false when no leaf node is selected', () => {
      const treeNode: TreeNodeModel = {
        label: 'root',
        isSelected: false,
        value: null,
        uuid: '0',
        children: [
          {
            label: '1evel 1',
            isSelected: false,
            value: null,
          },
          {
            label: 'level 1',
            isSelected: false,
            value: null,
            children: [
              {
                label: '1evel 2',
                isSelected: false,
                value: null,
              },
              {
                label: '1evel 2',
                isSelected: true,
                value: null,
                children: [
                  {
                    label: '1evel 3',
                    isSelected: false,
                    value: null,
                  },
                  {
                    label: '1evel 3',
                    isSelected: false,
                    value: null,
                  },
                ],
              },
            ],
          },
        ],
      };

      const result = service.hasSelectedLeafNodeDescendant(treeNode);

      expect(result).toBe(false);
    });
  });
});
