// =============================================================================
// TDD proof for the AereInsuranceFund LIFETIME-CAP CHECK ORDER fix (LOW).
//
// BUG: the lifetime-cap check ran on the REQUESTED amount BEFORE the
// clamp-to-owed step, so a legitimate coverage whose clamped amount is under
// the remaining cap was spuriously blocked with CapExceeded.
//
// FIX: fetch owed + clamp `amount` to it FIRST, then run the cap check on the
// ACTUAL (clamped) amount that will be paid. Cap semantics unchanged: total
// lifetime coverage per market <= cap.
//
// Uses MockDebtMarketForFund so the debt balance is pinned exactly (the real
// AereLendingMarket accrues per-second interest across the 7-day registration
// timelock, which would blur the cap boundary this test targets).
//
// Run in ISOLATION:
//   npx hardhat test test/insurance-fund-cap-clamp-order-fix.test.js
//
// No em-dashes in this file.
// =============================================================================

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

const ONE6 = 10n ** 6n;

describe("AereInsuranceFund - cap check applies to clamped amount (order fix)", function () {
  this.timeout(120000);

  async function deploy() {
    const [, foundation, bob, donor] = await ethers.getSigners();
    const ERC20 = await ethers.getContractFactory("MockERC20Lending");
    const debt = await ERC20.deploy("USDC.e", "USDC.e", 6);
    await debt.waitForDeployment();
    const Mock = await ethers.getContractFactory("MockDebtMarketForFund");
    const mkt = await Mock.deploy(await debt.getAddress());
    await mkt.waitForDeployment();
    const Fund = await ethers.getContractFactory("AereInsuranceFund");
    const fund = await Fund.deploy(foundation.address, 0); // no cooldown
    await fund.waitForDeployment();

    // Fund the pool with 1000 USDC.e.
    await debt.mint(donor.address, 1000n * ONE6);
    await debt.connect(donor).approve(await fund.getAddress(), 1000n * ONE6);
    await fund.connect(donor).donate(await debt.getAddress(), 1000n * ONE6);

    return { fund, mkt, debt, foundation, bob };
  }

  async function register(fund, foundation, mkt, cap) {
    await fund.connect(foundation).proposeMarket(await mkt.getAddress(), cap);
    await ethers.provider.send("evm_increaseTime", [7 * 86400 + 1]);
    await ethers.provider.send("evm_mine", []);
    await fund.connect(foundation).registerMarket(await mkt.getAddress());
  }

  it("request > owed but clamped amount < remaining cap now SUCCEEDS (pre-fix reverted CapExceeded)", async () => {
    const { fund, mkt, foundation, bob } = await deploy();
    const owed = 10n * ONE6;
    await mkt.setDebt(bob.address, owed);

    // cap (20) > owed (10); request (100) > cap.
    const cap = 20n * ONE6;
    await register(fund, foundation, mkt, cap);

    const request = 100n * ONE6;
    // Pre-fix: cap check on the request (100 > 20) -> CapExceeded.
    // Post-fix: clamp to owed (10) <= cap (20) -> pays exactly 10.
    await expect(
      fund.connect(foundation).coverBadDebt(await mkt.getAddress(), bob.address, request)
    ).to.emit(fund, "BadDebtCovered").withArgs(await mkt.getAddress(), bob.address, owed);

    const m = await fund.markets(await mkt.getAddress());
    expect(m.covered).to.equal(owed);
    expect(await mkt.debtBalance(bob.address)).to.equal(0n);
  });

  it("cap semantics preserved: clamped amount OVER the cap still reverts CapExceeded", async () => {
    const { fund, mkt, foundation, bob } = await deploy();
    const owed = 30n * ONE6;
    await mkt.setDebt(bob.address, owed);

    // cap (20) < owed (30): even after clamping to 30, 30 > 20 -> CapExceeded.
    const cap = 20n * ONE6;
    await register(fund, foundation, mkt, cap);

    await expect(
      fund.connect(foundation).coverBadDebt(await mkt.getAddress(), bob.address, 1000n * ONE6)
    ).to.be.revertedWithCustomError(fund, "CapExceeded");
  });

  it("cap accumulates across coverages on the clamped amounts", async () => {
    const { fund, mkt, foundation, bob } = await deploy();
    const [, , , , carol] = await ethers.getSigners();
    // cap 25; first cover clamps to 10, second to 12 -> total 22 <= 25 ok;
    // a third clamped 10 would push to 32 > 25 -> CapExceeded.
    const cap = 25n * ONE6;
    await register(fund, foundation, mkt, cap);

    await mkt.setDebt(bob.address, 10n * ONE6);
    await fund.connect(foundation).coverBadDebt(await mkt.getAddress(), bob.address, 1000n * ONE6);
    expect((await fund.markets(await mkt.getAddress())).covered).to.equal(10n * ONE6);

    await mkt.setDebt(carol.address, 12n * ONE6);
    await fund.connect(foundation).coverBadDebt(await mkt.getAddress(), carol.address, 1000n * ONE6);
    expect((await fund.markets(await mkt.getAddress())).covered).to.equal(22n * ONE6);

    await mkt.setDebt(bob.address, 10n * ONE6);
    await expect(
      fund.connect(foundation).coverBadDebt(await mkt.getAddress(), bob.address, 1000n * ONE6)
    ).to.be.revertedWithCustomError(fund, "CapExceeded");
  });
});
