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();
  });
});
