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

import {Test, console} from "forge-std/Test.sol";
import "../../../../contracts/bridge/trustless/integration/BridgeReserveCoordinator.sol";
import "../../../../contracts/bridge/trustless/BridgeSwapCoordinator.sol";
import "../../../../contracts/bridge/trustless/InboxETH.sol";
import "../../../../contracts/bridge/trustless/LiquidityPoolETH.sol";
import "../../../../contracts/bridge/trustless/ChallengeManager.sol";
import "../../../../contracts/bridge/trustless/BondManager.sol";
import "../../../../contracts/reserve/ReserveSystem.sol";
import "../../../../contracts/bridge/trustless/integration/StablecoinPegManager.sol";
import "../../../../contracts/bridge/trustless/integration/CommodityPegManager.sol";
import "../../../../contracts/bridge/trustless/integration/ISOCurrencyManager.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MockERC20 is ERC20 {
    constructor(string memory name, string memory symbol) ERC20(name, symbol) {
        _mint(msg.sender, 1000000 ether);
    }
    
    function mint(address to, uint256 amount) external {
        _mint(to, amount);
    }
}

contract BridgeReserveCoordinatorTest is Test {
    BridgeReserveCoordinator public coordinator;
    BridgeSwapCoordinator public bridgeSwapCoordinator;
    ReserveSystem public reserveSystem;
    StablecoinPegManager public stablecoinPegManager;
    CommodityPegManager public commodityPegManager;
    ISOCurrencyManager public isoCurrencyManager;
    
    // Existing bridge contracts
    InboxETH public inbox;
    LiquidityPoolETH public liquidityPool;
    ChallengeManager public challengeManager;
    BondManager public bondManager;

    // Mock tokens
    MockERC20 public usdt;
    MockERC20 public usdc;
    MockERC20 public weth;
    MockERC20 public xau;

    address public deployer = address(0xDE0001);
    address public user = address(0x1111);

    function setUp() public {
        vm.startPrank(deployer);

        // Deploy mock tokens
        usdt = new MockERC20("Tether USD", "USDT");
        usdc = new MockERC20("USD Coin", "USDC");
        weth = new MockERC20("Wrapped Ether", "WETH");
        xau = new MockERC20("Gold", "XAU");

        // Deploy ReserveSystem
        reserveSystem = new ReserveSystem(deployer);
        
        // Register assets in ReserveSystem (using grantRole for PRICE_FEED_ROLE)
        vm.stopPrank();
        vm.prank(deployer);
        reserveSystem.grantRole(keccak256("PRICE_FEED_ROLE"), address(this));
        vm.startPrank(address(this));
        
        // Set supported assets and prices
        // Note: ReserveSystem doesn't have addSupportedAsset, we'll use updatePriceFeed directly
        // which implicitly supports the asset

        // Set prices in ReserveSystem (mock)
        // Note: updatePriceFeed requires PRICE_FEED_ROLE
        vm.stopPrank();
        vm.startPrank(deployer);
        reserveSystem.grantRole(keccak256("PRICE_FEED_ROLE"), deployer);
        reserveSystem.updatePriceFeed(address(usdt), 1e18, block.timestamp); // $1.00
        reserveSystem.updatePriceFeed(address(usdc), 1e18, block.timestamp); // $1.00
        reserveSystem.updatePriceFeed(address(weth), 1e18, block.timestamp); // 1:1 with ETH
        reserveSystem.updatePriceFeed(address(xau), 2000e18, block.timestamp); // $2000/oz

        // Deploy StablecoinPegManager
        stablecoinPegManager = new StablecoinPegManager(address(reserveSystem));
        stablecoinPegManager.registerUSDStablecoin(address(usdt));
        stablecoinPegManager.registerUSDStablecoin(address(usdc));
        stablecoinPegManager.registerWETH(address(weth));

        // Deploy CommodityPegManager
        commodityPegManager = new CommodityPegManager(address(reserveSystem));
        commodityPegManager.setXAUAddress(address(xau));
        commodityPegManager.registerCommodity(address(xau), "XAU", 1e18); // 1:1 with itself

        // Deploy ISOCurrencyManager
        isoCurrencyManager = new ISOCurrencyManager(address(reserveSystem));
        isoCurrencyManager.setXAUAddress(address(xau));
        isoCurrencyManager.registerCurrency("USD", address(usdt), 2000e18); // 1 oz XAU = 2000 USD
        isoCurrencyManager.registerCurrency("EUR", address(0), 1800e18); // 1 oz XAU = 1800 EUR

        // Deploy existing bridge contracts (simplified setup)
        bondManager = new BondManager(11000, 1 ether);
        challengeManager = new ChallengeManager(address(bondManager), 30 minutes);
        liquidityPool = new LiquidityPoolETH(address(weth), 5, 11000);
        inbox = new InboxETH(address(bondManager), address(challengeManager), address(liquidityPool));
        
        // Create a mock SwapRouter address (we won't actually use it in these tests)
        address mockSwapRouter = address(0x1234567890123456789012345678901234567890);
        bridgeSwapCoordinator = new BridgeSwapCoordinator(
            address(inbox),
            address(liquidityPool),
            mockSwapRouter,
            address(challengeManager)
        );

        // Deploy BridgeReserveCoordinator
        coordinator = new BridgeReserveCoordinator(
            address(bridgeSwapCoordinator),
            address(reserveSystem),
            address(stablecoinPegManager),
            address(commodityPegManager),
            address(isoCurrencyManager)
        );

        // Deposit reserves
        usdt.approve(address(reserveSystem), 100000 ether);
        reserveSystem.depositReserve(address(usdt), 100000 ether);

        vm.stopPrank();
    }

    function testVerifyReserveStatus() public {
        uint256 bridgeAmount = 1000 ether;
        
        BridgeReserveCoordinator.ReserveStatus memory status = coordinator.getReserveStatus(
            address(usdt),
            bridgeAmount
        );

        assertEq(status.asset, address(usdt));
        assertEq(status.bridgeAmount, bridgeAmount);
        assertGt(status.reserveBalance, 0);
        assertTrue(status.isSufficient);
    }

    function testVerifyPegStatus() public {
        BridgeReserveCoordinator.PegStatus[] memory pegStatuses = coordinator.verifyPegStatus();
        
        assertGt(pegStatuses.length, 0);
        
        // Check that we have stablecoin peg statuses
        bool foundUSDT = false;
        for (uint256 i = 0; i < pegStatuses.length; i++) {
            if (pegStatuses[i].asset == address(usdt)) {
                foundUSDT = true;
                assertEq(pegStatuses[i].targetPrice, 1e18); // $1.00
                break;
            }
        }
        assertTrue(foundUSDT);
    }

    function testSetReserveThreshold() public {
        uint256 newThreshold = 11000; // 110%
        
        vm.prank(deployer);
        coordinator.setReserveThreshold(newThreshold);
        
        assertEq(coordinator.reserveVerificationThresholdBps(), newThreshold);
    }

    function testRevertInvalidReserveThreshold() public {
        uint256 invalidThreshold = 20000; // 200% > max 150%
        
        vm.prank(deployer);
        vm.expectRevert(BridgeReserveCoordinator.InvalidReserveThreshold.selector);
        coordinator.setReserveThreshold(invalidThreshold);
    }
}

