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

import {Test} from "forge-std/Test.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import {SimpleERC3156FlashVault} from "../../contracts/flash/SimpleERC3156FlashVault.sol";
import {SwapFlashWorkflowBorrower, IDODOStyleSwapExactIn} from "../../contracts/flash/SwapFlashWorkflowBorrower.sol";

/// @notice 1:1 swap router for tests (ignores pool).
contract MockSwapRouter1to1 is IDODOStyleSwapExactIn {
    ERC20 public immutable tokenA;
    ERC20 public immutable tokenB;

    constructor(ERC20 a, ERC20 b) {
        tokenA = a;
        tokenB = b;
    }

    function swapExactIn(address, address tokenIn, uint256 amountIn, uint256 minAmountOut)
        external
        override
        returns (uint256 amountOut)
    {
        IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
        address tokenOut = tokenIn == address(tokenA) ? address(tokenB) : address(tokenA);
        amountOut = amountIn;
        require(amountOut >= minAmountOut, "min");
        IERC20(tokenOut).transfer(msg.sender, amountOut);
    }
}

contract MockERC20Mint is ERC20 {
    constructor(string memory n, string memory s) ERC20(n, s) {}

    function mint(address to, uint256 v) external {
        _mint(to, v);
    }
}

contract SwapFlashWorkflowBorrowerTest is Test {
    SimpleERC3156FlashVault internal vault;
    MockERC20Mint internal tokenA;
    MockERC20Mint internal tokenB;
    MockSwapRouter1to1 internal router;
    SwapFlashWorkflowBorrower internal borrower;

    address internal owner = address(0xA11);
    address internal user = address(0xB22);

    function setUp() public {
        vm.startPrank(owner);
        vault = new SimpleERC3156FlashVault(owner, 5);
        tokenA = new MockERC20Mint("A", "A");
        tokenB = new MockERC20Mint("B", "B");
        tokenA.mint(address(vault), 1_000_000e18);
        vault.setTokenSupported(address(tokenA), true);
        vm.stopPrank();

        router = new MockSwapRouter1to1(tokenA, tokenB);
        tokenA.mint(address(router), 10_000_000e18);
        tokenB.mint(address(router), 10_000_000e18);

        borrower = new SwapFlashWorkflowBorrower(address(vault));
    }

    function test_roundTripSwap_prefundFeeInBorrowedToken() public {
        uint256 amount = 50_000e18;
        uint256 fee = vault.flashFee(address(tokenA), amount);
        tokenA.mint(address(borrower), fee);

        SwapFlashWorkflowBorrower.SwapFlashParams memory p = SwapFlashWorkflowBorrower.SwapFlashParams({
            integration: address(router),
            pool: address(0xdead),
            midToken: address(tokenB),
            minOutFirst: amount,
            minOutSecond: amount
        });
        bytes memory data = abi.encode(p);

        vm.prank(user);
        vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(tokenA), amount, data);

        assertEq(vault.totalFeesCollected(address(tokenA)), fee);
    }
}
