// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Test} from "forge-std/Test.sol";

import {OfficialStableMirrorToken} from "../../contracts/tokens/OfficialStableMirrorToken.sol";
import {CompliantUSDT} from "../../contracts/tokens/CompliantUSDT.sol";
import {CompliantUSDC} from "../../contracts/tokens/CompliantUSDC.sol";
import {StablecoinReserveVault} from "../../contracts/reserve/StablecoinReserveVault.sol";

contract StablecoinReserveVaultTest is Test {
    address internal user = address(0xBEEF);

    OfficialStableMirrorToken internal officialUsdt;
    OfficialStableMirrorToken internal officialUsdc;
    CompliantUSDT internal compliantUsdt;
    CompliantUSDC internal compliantUsdc;
    StablecoinReserveVault internal vault;

    function setUp() public {
        officialUsdt = new OfficialStableMirrorToken("Tether USD (Chain 138)", "USDT", 6, address(this), 0);
        officialUsdc = new OfficialStableMirrorToken("USD Coin (Chain 138)", "USDC", 6, address(this), 0);
        compliantUsdt = new CompliantUSDT(address(this), address(this));
        compliantUsdc = new CompliantUSDC(address(this), address(this));
        vault = new StablecoinReserveVault(
            address(this),
            address(officialUsdt),
            address(officialUsdc),
            address(compliantUsdt),
            address(compliantUsdc)
        );
    }

    function testSeedReserveBootstrapsBackingForExistingCanonicalSupply() public {
        uint256 existingCusdtSupply = compliantUsdt.totalSupply();
        uint256 existingCusdcSupply = compliantUsdc.totalSupply();

        officialUsdt.mint(address(this), existingCusdtSupply);
        officialUsdc.mint(address(this), existingCusdcSupply);

        officialUsdt.approve(address(vault), existingCusdtSupply);
        officialUsdc.approve(address(vault), existingCusdcSupply);

        vault.seedUSDTReserve(existingCusdtSupply);
        vault.seedUSDCReserve(existingCusdcSupply);

        (uint256 usdtReserve, uint256 usdtSupply, uint256 usdtBackingRatio) =
            vault.getBackingRatio(address(compliantUsdt));
        (uint256 usdcReserve, uint256 usdcSupply, uint256 usdcBackingRatio) =
            vault.getBackingRatio(address(compliantUsdc));

        assertEq(usdtReserve, existingCusdtSupply);
        assertEq(usdtSupply, existingCusdtSupply);
        assertEq(usdtBackingRatio, 10000);

        assertEq(usdcReserve, existingCusdcSupply);
        assertEq(usdcSupply, existingCusdcSupply);
        assertEq(usdcBackingRatio, 10000);

        (bool usdtAdequate, bool usdcAdequate) = vault.checkReserveAdequacy();
        assertTrue(usdtAdequate);
        assertTrue(usdcAdequate);
    }

    function testDepositAndRedeemWorkAfterVaultTakesCompliantOwnership() public {
        uint256 depositAmount = 100e6;
        uint256 redeemAmount = 40e6;

        compliantUsdt.transferOwnership(address(vault));

        officialUsdt.mint(user, depositAmount);

        vm.startPrank(user);
        officialUsdt.approve(address(vault), depositAmount);
        vault.depositUSDT(depositAmount);
        assertEq(compliantUsdt.balanceOf(user), depositAmount);
        assertEq(officialUsdt.balanceOf(user), 0);

        compliantUsdt.approve(address(vault), redeemAmount);
        vault.redeemUSDT(redeemAmount);
        vm.stopPrank();

        assertEq(compliantUsdt.balanceOf(user), depositAmount - redeemAmount);
        assertEq(officialUsdt.balanceOf(user), redeemAmount);
        assertEq(vault.usdtReserveBalance(), depositAmount - redeemAmount);
    }

    function testVaultAdminCanRecoverCompliantTokenOwnership() public {
        address recoveryOwner = address(0xCAFE);

        compliantUsdc.transferOwnership(address(vault));
        assertEq(compliantUsdc.owner(), address(vault));

        vault.transferCompliantTokenOwnership(address(compliantUsdc), recoveryOwner);
        assertEq(compliantUsdc.owner(), recoveryOwner);
    }
}
