// AereHybridAuth — unit tests.
//
// The Falcon-512 leg is mocked here (real Falcon signatures cannot be produced
// inside the hardhat process); the REAL end-to-end Falcon verification is
// demonstrated on AERE mainnet against the live AereFalcon512Verifier by
// scripts/deploy-hybrid-auth.js. These tests pin the ECDSA leg + the "requires
// BOTH legs" composition logic.

const { expect } = require("chai");
const { ethers } = require("hardhat");

// 897-byte NIST Falcon-512 public key placeholder (0x09 header). The mock does
// not decode it; the on-chain demo uses a genuine reference-generated key.
function fakeFalconPk() {
  const b = new Uint8Array(897);
  b[0] = 0x09;
  for (let i = 1; i < 897; i++) b[i] = (i * 7) & 0xff;
  return ethers.hexlify(b);
}

const NONCE = "0x" + "ab".repeat(40);
const COMPSIG = "0x" + "cd".repeat(600);

describe("AereHybridAuth", function () {
  let auth, falcon, signer, other;
  const ID = ethers.id("identity-1");
  const pk = fakeFalconPk();

  beforeEach(async function () {
    [, signer, other] = await ethers.getSigners();
    const M = await ethers.getContractFactory("MockFalcon512Verifier");
    falcon = await M.deploy();
    await falcon.waitForDeployment();
    const A = await ethers.getContractFactory("AereHybridAuth");
    auth = await A.deploy(await falcon.getAddress());
    await auth.waitForDeployment();
    await auth.registerIdentity(ID, signer.address, pk);
  });

  it("registers a hybrid identity and rejects bad Falcon pubkeys", async function () {
    const [reg, ecdsa, storedPk] = await auth.getIdentity(ID);
    expect(reg).to.equal(true);
    expect(ecdsa).to.equal(signer.address);
    expect(storedPk).to.equal(pk);
    expect(await auth.identityCount()).to.equal(1n);

    await expect(auth.registerIdentity(ID, signer.address, pk)).to.be.revertedWithCustomError(auth, "AlreadyRegistered");
    // wrong length
    await expect(
      auth.registerIdentity(ethers.id("id2"), signer.address, "0x0900")
    ).to.be.revertedWithCustomError(auth, "BadFalconPubKey");
    // wrong header
    const badHdr = ethers.hexlify(new Uint8Array(897));
    await expect(
      auth.registerIdentity(ethers.id("id3"), signer.address, badHdr)
    ).to.be.revertedWithCustomError(auth, "BadFalconPubKey");
  });

  async function ecdsaSig(wallet, messageHash) {
    // EIP-191 personal-sign of the 32-byte messageHash.
    return wallet.signMessage(ethers.getBytes(messageHash));
  }

  it("authorizes only when BOTH ECDSA and Falcon verify", async function () {
    const messageHash = ethers.id("action:transfer-1000");
    const falconMsg = messageHash; // contract signs abi.encodePacked(messageHash)
    const good = await ecdsaSig(signer, messageHash);

    // Falcon mock accepts this exact tuple.
    await falcon.setResult(pk, falconMsg, NONCE, COMPSIG, true);

    // both good -> accepted
    let [e, f, ok] = await auth.checkHybrid(ID, messageHash, good, NONCE, COMPSIG);
    expect(e).to.equal(true);
    expect(f).to.equal(true);
    expect(ok).to.equal(true);

    const tx = await auth.authorize(ID, messageHash, good, NONCE, COMPSIG);
    await tx.wait();
    expect(await auth.isAuthorized(ID, messageHash)).to.equal(true);
    expect(await auth.authCount()).to.equal(1n);
    expect(await auth.lastMessageHash()).to.equal(messageHash);
  });

  it("rejects when the Falcon leg fails (wrong/tampered PQC sig)", async function () {
    const messageHash = ethers.id("action:transfer-2000");
    const good = await ecdsaSig(signer, messageHash);
    // Falcon mock rejects (default false, no override).
    const [e, f, ok] = await auth.checkHybrid(ID, messageHash, good, NONCE, COMPSIG);
    expect(e).to.equal(true);
    expect(f).to.equal(false);
    expect(ok).to.equal(false);
    await expect(auth.authorize(ID, messageHash, good, NONCE, COMPSIG))
      .to.be.revertedWithCustomError(auth, "HybridAuthFailed")
      .withArgs(true, false);
  });

  it("rejects when the ECDSA leg fails (wrong classical signer)", async function () {
    const messageHash = ethers.id("action:transfer-3000");
    const falconMsg = messageHash;
    await falcon.setResult(pk, falconMsg, NONCE, COMPSIG, true); // Falcon would pass
    const wrong = await ecdsaSig(other, messageHash); // signed by the wrong key
    const [e, f, ok] = await auth.checkHybrid(ID, messageHash, wrong, NONCE, COMPSIG);
    expect(e).to.equal(false);
    expect(f).to.equal(true);
    expect(ok).to.equal(false);
    await expect(auth.authorize(ID, messageHash, wrong, NONCE, COMPSIG))
      .to.be.revertedWithCustomError(auth, "HybridAuthFailed")
      .withArgs(false, true);
  });

  it("reverts checking an unregistered identity", async function () {
    const messageHash = ethers.id("x");
    const good = await ecdsaSig(signer, messageHash);
    await expect(
      auth.checkHybrid(ethers.id("nope"), messageHash, good, NONCE, COMPSIG)
    ).to.be.revertedWithCustomError(auth, "NotRegistered");
  });
});
