import { GroupConfigBlock, GroupConfigBlockMemberFlags } from './group_config/block';
import { GroupConfigBlockChain } from './group_config/chain';
import { FlagParser, MemberPermissions } from './group_config/chain-flag-parser';
import { SelfAccountKeyring } from './keyring/account_self';

describe('FlagParser test', () => {
  let selfKr: SelfAccountKeyring;
  let chain: GroupConfigBlockChain;

  function addBlock(chain: GroupConfigBlockChain, selfKr: SelfAccountKeyring, flags: Object) {
    return chain
      .new_block(selfKr, 'A', flags, 0)
      .then(([newBlock, newBlockSignature, memberDeltas, groupDeltas]) => {
        return chain.load_block(newBlock, newBlockSignature, selfKr);
      });
  }

  beforeEach((done) => {
    selfKr = SelfAccountKeyring.generate('acc0');
    GroupConfigBlockChain.load('24GBVjw422222', [], selfKr).then((c) => {
      chain = c;
      done();
    });
  });

  it('check the empty flag-parser', () => {
    expect(new FlagParser(chain).getMembersPermissions().size == 0).toBeTrue();
  });

  it('check one member', async () => {
    await addBlock(chain, selfKr, {
      a: GroupConfigBlockMemberFlags.ACTIVE,
    });

    expect(new FlagParser(chain).getMembersPermissions().size == 1).toBeTrue();
  });

  it('check 3 member', async () => {
    await addBlock(chain, selfKr, {
      a: GroupConfigBlockMemberFlags.ACTIVE,
      b: GroupConfigBlockMemberFlags.ACTIVE,
      c: GroupConfigBlockMemberFlags.ACTIVE,
    });

    expect(new FlagParser(chain).getMembersPermissions().size == 3).toBeTrue();
  });

  it('check one member flags - active', async () => {
    await addBlock(chain, selfKr, {
      a: GroupConfigBlockMemberFlags.ACTIVE,
    });

    let flags = new FlagParser(chain).getMembersPermissions();
    expect(
      flags.size == 1 &&
        flags.get('a').isActive &&
        !flags.get('a').isAdmin &&
        !flags.get('a').canAdhocDrive &&
        !flags.get('a').canWriteDrive
    ).toBeTrue();
  });

  it('check one member flags - admin', async () => {
    await addBlock(chain, selfKr, {
      a: GroupConfigBlockMemberFlags.ACTIVE | GroupConfigBlockMemberFlags.ADMINISTRATOR,
    });

    let flags = new FlagParser(chain).getMembersPermissions();

    expect(
      flags.size == 1 &&
        flags.get('a').isActive &&
        flags.get('a').isAdmin &&
        !flags.get('a').canAdhocDrive &&
        !flags.get('a').canWriteDrive
    ).toBeTrue();
  });

  it('check one member flags - adhoc', async () => {
    await addBlock(chain, selfKr, {
      a: GroupConfigBlockMemberFlags.ACTIVE | GroupConfigBlockMemberFlags.DRIVE_ADHOC,
    });

    let flags = new FlagParser(chain).getMembersPermissions();

    expect(
      flags.size == 1 &&
        flags.get('a').isActive &&
        !flags.get('a').isAdmin &&
        flags.get('a').canAdhocDrive &&
        !flags.get('a').canWriteDrive
    ).toBeTrue();
  });

  it('check one member flags - drive', async () => {
    await addBlock(chain, selfKr, {
      a: GroupConfigBlockMemberFlags.ACTIVE | GroupConfigBlockMemberFlags.DRIVE_WRITE,
    });

    let flags = new FlagParser(chain).getMembersPermissions();

    expect(
      flags.size == 1 &&
        flags.get('a').isActive &&
        !flags.get('a').isAdmin &&
        !flags.get('a').canAdhocDrive &&
        flags.get('a').canWriteDrive
    ).toBeTrue();
  });

  it('check one member flags - all', async () => {
    await addBlock(chain, selfKr, {
      a:
        GroupConfigBlockMemberFlags.ACTIVE |
        GroupConfigBlockMemberFlags.DRIVE_WRITE |
        GroupConfigBlockMemberFlags.DRIVE_ADHOC |
        GroupConfigBlockMemberFlags.ADMINISTRATOR,
    });

    let flags = new FlagParser(chain).getMembersPermissions();

    expect(
      flags.size == 1 &&
        flags.get('a').isActive &&
        flags.get('a').isAdmin &&
        flags.get('a').canAdhocDrive &&
        flags.get('a').canWriteDrive
    ).toBeTrue();
  });

  /*
  let allFlags: MemberPermissions = {
    isActive: false,
    isAdmin: false,
    canAdhocDrive: false,
    canWriteDrive: false,
    canUploadDrive: false,
    isModerator: false,
  };

  let flagFlag: { [key: string]: { pos: number; negate: number } } = {
    isActive: {
      pos: GroupConfigBlockMemberFlags.ACTIVE,
      negate: GroupConfigBlockMemberFlags.ACTIVE_NEGATE,
    },
    isAdmin: {
      pos: GroupConfigBlockMemberFlags.ADMINISTRATOR,
      negate: GroupConfigBlockMemberFlags.ADMINISTRATOR_NEGATE,
    },
    canAdhocDrive: {
      pos: GroupConfigBlockMemberFlags.DRIVE_ADHOC,
      negate: GroupConfigBlockMemberFlags.DRIVE_ADHOC_NEGATE,
    },
    canWriteDrive: {
      pos: GroupConfigBlockMemberFlags.DRIVE_WRITE,
      negate: GroupConfigBlockMemberFlags.DRIVE_WRITE_NEGATE,
    },
    canUploadDrive: {
      pos: GroupConfigBlockMemberFlags.DRIVE_UPLOAD,
      negate: GroupConfigBlockMemberFlags.DRIVE_UPLOAD_NEGATE,
    },
  };

  let permissions = Object.keys(allFlags).filter((key) => {
    return !["isModerator"].includes(key);
  });

  for (let i = 0; i < permissions.length; i++) {
    let flags;
    it("check parseToFlags " + permissions[i], (done) => {
      flags = FlagParser.parseToFlags(
        allFlags,
        Object.assign(
          Object.assign(Object.assign({}, allFlags), { isActive: true }),
          {
            [permissions[i]]: true,
          }
        )
      );

      permissions.forEach((perm)=>{
        if (permissions[i] == perm){
          expect((flags & flagFlag[permissions[i]].negate) != 0).toBeTrue();
        }
        else{
          expect((flags & flagFlag[perm].negate) == 0).toBeTrue();
        }
      })
    });

    it("check parseToFlags " + permissions[i], () => {
      flags = FlagParser.parseToFlags(
        allFlags,
        Object.assign(
          Object.assign(Object.assign({}, allFlags), { isActive: true }),
          {
            [permissions[i]]: true,
          }
        )
      );

      expect((flags & flagFlag[permissions[i]].negate) != 0).toBeTrue();
    });
  }*/

  it('check parseToFlags inactive', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: false,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect((flags & GroupConfigBlockMemberFlags.ACTIVE_NEGATE) != 0).toBeTrue();
  });

  it('check parseToFlags active', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: false,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.ACTIVE_NEGATE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE) != 1
    ).toBeTrue();
  });

  it('check parseToFlags admin', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: true,
        isAdmin: true,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.ADMINISTRATOR) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ADMINISTRATOR_NEGATE) != 1 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE_NEGATE) != 1
    ).toBeTrue();
  });

  it('check parseToFlags admin negate', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: true,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.ADMINISTRATOR) != 1 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ADMINISTRATOR_NEGATE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE_NEGATE) != 1
    ).toBeTrue();
  });

  it('check parseToFlags can adhoc', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: true,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.DRIVE_ADHOC) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.DRIVE_ADHOC_NEGATE) != 1 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE_NEGATE) != 1
    ).toBeTrue();
  });

  it('check parseToFlags can adhoc negate', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: true,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.DRIVE_ADHOC) != 1 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.DRIVE_ADHOC_NEGATE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE_NEGATE) != 1
    ).toBeTrue();
  });

  it('check parseToFlags can drive', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: true,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.DRIVE_WRITE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.DRIVE_WRITE_NEGATE) != 1 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE_NEGATE) != 1
    ).toBeTrue();
  });

  it('check parseToFlags can drive negate', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: true,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.DRIVE_WRITE) != 1 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.DRIVE_WRITE_NEGATE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ACTIVE_NEGATE) != 1
    ).toBeTrue();
  });

  it('check parseToFlags all', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: true,
        isAdmin: true,
        canAdhocDrive: true,
        canWriteDrive: true,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.ACTIVE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.DRIVE_WRITE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.ADMINISTRATOR) != 0 &&
        (flags & GroupConfigBlockMemberFlags.DRIVE_ADHOC) != 0
    ).toBeTrue();
  });

  it('check parseToFlags all negate', () => {
    let flags = FlagParser.parseToFlags(
      {
        isActive: true,
        isAdmin: true,
        canAdhocDrive: true,
        canWriteDrive: true,
        canUploadDrive: false,
        isModerator: false,
      },
      {
        isActive: true,
        isAdmin: false,
        canAdhocDrive: false,
        canWriteDrive: false,
        canUploadDrive: false,
        isModerator: false,
      }
    );
    expect(
      (flags & GroupConfigBlockMemberFlags.ACTIVE) != 0 &&
        (flags & GroupConfigBlockMemberFlags.DRIVE_WRITE_NEGATE) != 1 &&
        (flags & GroupConfigBlockMemberFlags.ADMINISTRATOR_NEGATE) != 1 &&
        (flags & GroupConfigBlockMemberFlags.DRIVE_ADHOC_NEGATE) != 1
    ).toBeTrue();
  });
});
