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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../../../liquidity/interfaces/ILiquidityProvider.sol";
import "../RouteTypesV2.sol";
import "../interfaces/IRouteExecutorAdapter.sol";

contract DodoRouteExecutorAdapter is IRouteExecutorAdapter {
    using SafeERC20 for IERC20;

    function validate(
        RouteTypesV2.RouteLeg calldata leg
    ) external view override returns (bool ok, string memory reason) {
        if (leg.provider != RouteTypesV2.Provider.Dodo) {
            return (false, "DodoRouteExecutorAdapter: invalid provider");
        }
        if (leg.target == address(0)) {
            return (false, "DodoRouteExecutorAdapter: zero target");
        }
        if (leg.tokenIn == address(0) || leg.tokenOut == address(0)) {
            return (false, "DodoRouteExecutorAdapter: zero token");
        }
        if (leg.providerData.length != 32) {
            return (false, "DodoRouteExecutorAdapter: invalid providerData");
        }

        address poolAddress = abi.decode(leg.providerData, (address));
        if (poolAddress == address(0)) {
            return (false, "DodoRouteExecutorAdapter: zero pool");
        }
        if (!ILiquidityProvider(leg.target).supportsTokenPair(leg.tokenIn, leg.tokenOut)) {
            return (false, "DodoRouteExecutorAdapter: unsupported pair");
        }
        return (true, "");
    }

    function quote(
        RouteTypesV2.RouteLeg calldata leg,
        uint256 amountIn
    ) external view override returns (uint256 amountOut, uint256 gasEstimate) {
        (amountOut,) = ILiquidityProvider(leg.target).getQuote(leg.tokenIn, leg.tokenOut, amountIn);
        gasEstimate = ILiquidityProvider(leg.target).estimateGas(leg.tokenIn, leg.tokenOut, amountIn);
    }

    function execute(
        RouteTypesV2.RouteLeg calldata leg,
        uint256 amountIn
    ) external override returns (uint256 amountOut) {
        IERC20(leg.tokenIn).forceApprove(leg.target, 0);
        IERC20(leg.tokenIn).forceApprove(leg.target, amountIn);
        amountOut = ILiquidityProvider(leg.target).executeSwap(
            leg.tokenIn,
            leg.tokenOut,
            amountIn,
            leg.minAmountOut
        );
        IERC20(leg.tokenOut).safeTransfer(msg.sender, amountOut);
    }
}
