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

import {Test} from "forge-std/Test.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {TwoHopDodoToUniswapV3MultiHopExternalUnwinder} from "../../contracts/flash/TwoHopDodoToUniswapV3MultiHopExternalUnwinder.sol";

contract TwoHopDodoToUniswapV3MultiHopExternalUnwinderMainnetForkTest is Test {
    address constant DODO_PMM_INTEGRATION_MAINNET = 0xa9F284eD010f4F7d7F8F201742b49b9f58e29b84;
    address constant UNISWAP_V3_ROUTER = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
    address constant POOL_CWUSDT_CWUSDC = 0xe944b7Cb012A0820c07f54D51e92f0e1C74168DB;
    address constant POOL_CWUSDT_USDT = 0x79156F6B7bf71a1B72D78189B540A89A6C13F6FC;
    address constant CWUSDC = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a;
    address constant CWUSDT = 0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE;
    address constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
    address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;

    bytes constant USDT_TO_USDC_0_01_PATH =
        hex"dac17f958d2ee523a2206206994597c13d831ec7000064a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48";

    bool public forkAvailable;
    TwoHopDodoToUniswapV3MultiHopExternalUnwinder internal unwinder;

    modifier skipIfNoFork() {
        if (!forkAvailable) {
            return;
        }
        _;
    }

    function setUp() public {
        string memory rpcUrl = vm.envOr("ETHEREUM_MAINNET_RPC", string(""));
        if (bytes(rpcUrl).length == 0) {
            forkAvailable = false;
            return;
        }
        try vm.createSelectFork(rpcUrl) {
            forkAvailable = true;
        } catch {
            forkAvailable = false;
            return;
        }

        unwinder = new TwoHopDodoToUniswapV3MultiHopExternalUnwinder(DODO_PMM_INTEGRATION_MAINNET, UNISWAP_V3_ROUTER);
    }

    function testFork_cWUSDCToUSDC_unwindsThroughTwoDodoHopsThenV3() public skipIfNoFork {
        uint256 amountIn = 100_000; // 0.1 cWUSDC
        deal(CWUSDC, address(this), amountIn);
        IERC20(CWUSDC).approve(address(unwinder), amountIn);

        uint256 before = IERC20(USDC).balanceOf(address(this));
        uint256 amountOut = unwinder.unwind(
            CWUSDC,
            USDC,
            amountIn,
            1,
            abi.encode(POOL_CWUSDT_CWUSDC, POOL_CWUSDT_USDT, CWUSDT, 1, USDT, 1, USDT_TO_USDC_0_01_PATH)
        );
        uint256 afterBal = IERC20(USDC).balanceOf(address(this));

        assertGt(amountOut, 0, "amountOut > 0");
        assertEq(afterBal - before, amountOut, "USDC received");
    }
}
