import Client from '../dist/node/mina-signer/mina-signer.js';
import type { PrivateKey } from '../dist/node/mina-signer/src/types.js';

describe('Message', () => {
  describe('Mainnet network', () => {
    let client: Client;
    let privateKey: PrivateKey;

    beforeAll(async () => {
      client = new Client({ network: 'mainnet' });
      ({ privateKey } = client.genKeys());
    });

    it('generates a signed message', () => {
      const message = client.signMessage('hello', privateKey);
      expect(message.data).toBeDefined();
      expect(message.signature).toBeDefined();
    });

    it('generates a signed message by using signTransaction', () => {
      const message = client.signTransaction('hello', privateKey);
      expect(message.data).toBeDefined();
      expect(message.signature).toBeDefined();
    });

    it('verifies a signed message', () => {
      const message = client.signMessage('hello', privateKey);
      const verifiedMessage = client.verifyMessage(message);
      expect(verifiedMessage).toBeTruthy();
      expect(client.verifyTransaction(message)).toEqual(true);
    });

    it('verifies a signed message generated by signTransaction', () => {
      const message = client.signTransaction('hello', privateKey);
      const verifiedMessage = client.verifyMessage(message);
      expect(verifiedMessage).toBeTruthy();
      expect(client.verifyTransaction(message)).toEqual(true);
    });

    it('does not verify a signed message from `devnet`', () => {
      const message = client.signMessage('hello', privateKey);
      const devnetClient = new Client({ network: 'devnet' });
      const invalidMessage = devnetClient.verifyMessage(message);
      expect(invalidMessage).toBeFalsy();
      expect(devnetClient.verifyTransaction(message)).toEqual(false);
    });

    it('does not verify a signed message from `testnet`', () => {
      const message = client.signMessage('hello', privateKey);
      const testnetClient = new Client({ network: 'testnet' });
      const invalidMessage = testnetClient.verifyMessage(message);
      expect(invalidMessage).toBeFalsy();
      expect(testnetClient.verifyTransaction(message)).toEqual(false);
    });
  });

  describe('Devnet network', () => {
    let client: Client;
    let privateKey: PrivateKey;

    beforeAll(async () => {
      client = new Client({ network: 'devnet' });
      ({ privateKey } = client.genKeys());
    });

    it('generates a signed message', () => {
      const message = client.signMessage('hello', privateKey);
      expect(message.data).toBeDefined();
      expect(message.signature).toBeDefined();
    });

    it('generates a signed message by using signTransaction', () => {
      const message = client.signTransaction('hello', privateKey);
      expect(message.data).toBeDefined();
      expect(message.signature).toBeDefined();
    });

    it('verifies a signed message', () => {
      const message = client.signMessage('hello', privateKey);
      const verifiedMessage = client.verifyMessage(message);
      expect(verifiedMessage).toBeTruthy();
      expect(client.verifyTransaction(message)).toEqual(true);
    });

    it('verifies a signed message generated by signTransaction', () => {
      const message = client.signTransaction('hello', privateKey);
      const verifiedMessage = client.verifyMessage(message);
      expect(verifiedMessage).toBeTruthy();
      expect(client.verifyTransaction(message)).toEqual(true);
    });

    it('does not verify a signed message from `mainnet`', () => {
      const message = client.signMessage('hello', privateKey);
      const mainnetClient = new Client({ network: 'mainnet' });
      const invalidMessage = mainnetClient.verifyMessage(message);
      expect(invalidMessage).toBeFalsy();
      expect(mainnetClient.verifyTransaction(message)).toEqual(false);
    });
  });

  describe('Testnet network', () => {
    let testnetClient: Client;
    let devnetClient: Client;
    let privateKey: PrivateKey;

    beforeAll(async () => {
      testnetClient = new Client({ network: 'testnet' });
      devnetClient = new Client({ network: 'devnet' });
      ({ privateKey } = devnetClient.genKeys());
    });

    it('generates the same signatures as devnet', () => {
      const testnetMessage = testnetClient.signMessage('hello', privateKey);
      const devnetMessage = devnetClient.signMessage('hello', privateKey);
      expect(testnetMessage).toEqual(devnetMessage);
    });

    it('generates the same signatures as devnet using signTransaction', () => {
      const testnetMessage = testnetClient.signTransaction('hello', privateKey);
      const devnetMessage = devnetClient.signTransaction('hello', privateKey);
      expect(testnetMessage).toEqual(devnetMessage);
    });

    it('verifies a signed message from devnet and vice versa', () => {
      const testnetMessage = testnetClient.signMessage('hello', privateKey);
      const devnetMessage = devnetClient.signMessage('hello', privateKey);

      const verifiedDevnetMessage = testnetClient.verifyMessage(devnetMessage);
      const verifiedTestnetMessage = devnetClient.verifyMessage(testnetMessage);
      expect(verifiedDevnetMessage).toBeTruthy();
      expect(verifiedTestnetMessage).toBeTruthy();

      expect(testnetClient.verifyTransaction(devnetMessage)).toEqual(true);
      expect(devnetClient.verifyTransaction(testnetMessage)).toEqual(true);
    });

    it('verifies a signed message generated by signTransaction from devnet and vice versa', () => {
      const testnetMessage = testnetClient.signTransaction('hello', privateKey);
      const devnetMessage = devnetClient.signTransaction('hello', privateKey);

      const verifiedDevnetMessage = testnetClient.verifyMessage(devnetMessage);
      const verifiedTestnetMessage = devnetClient.verifyMessage(testnetMessage);
      expect(verifiedDevnetMessage).toBeTruthy();
      expect(verifiedTestnetMessage).toBeTruthy();

      expect(testnetClient.verifyTransaction(devnetMessage)).toEqual(true);
      expect(devnetClient.verifyTransaction(testnetMessage)).toEqual(true);
    });

    it('does not verify a signed message from `mainnet`', () => {
      const message = testnetClient.signMessage('hello', privateKey);
      const mainnetClient = new Client({ network: 'mainnet' });
      const invalidMessage = mainnetClient.verifyMessage(message);
      expect(invalidMessage).toBeFalsy();
      expect(mainnetClient.verifyTransaction(message)).toEqual(false);
    });
  });
});
