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

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {UniversalCCIPBridge} from "../bridge/UniversalCCIPBridge.sol";
import {ICrossChainFlashBridge} from "./interfaces/ICrossChainFlashBridge.sol";

/**
 * @title UniversalCCIPFlashBridgeAdapter
 * @notice Pulls `token` from the caller (e.g. `CrossChainFlashBorrower`) and forwards a `UniversalCCIPBridge.bridge` call.
 * @dev `extraData` (see `ICrossChainFlashBridge`): if empty, uses `assetType = 0`, `usePMM/useVault = false`, empty proofs.
 *      If non-empty: `abi.encode(bytes32 assetType, bool usePMM, bool useVault, bytes complianceProof, bytes vaultInstructions)`.
 *      Native value is forwarded for CCIP fees on the underlying bridge.
 */
contract UniversalCCIPFlashBridgeAdapter is ICrossChainFlashBridge {
    using SafeERC20 for IERC20;

    UniversalCCIPBridge public immutable universalBridge;

    constructor(address universalBridge_) {
        require(universalBridge_ != address(0), "UniversalCCIPFlashBridgeAdapter: zero bridge");
        universalBridge = UniversalCCIPBridge(payable(universalBridge_));
    }

    function bridgeTokensFrom(
        address token,
        uint256 amount,
        uint64 destinationChainSelector,
        address recipientOnDestination,
        bytes calldata extraData
    ) external payable override returns (bytes32 messageId) {
        IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
        IERC20(token).forceApprove(address(universalBridge), amount);

        bytes32 assetType;
        bool usePMM;
        bool useVault;
        bytes memory complianceProof;
        bytes memory vaultInstructions;

        if (extraData.length == 0) {
            assetType = bytes32(0);
            usePMM = false;
            useVault = false;
            complianceProof = "";
            vaultInstructions = "";
        } else {
            (assetType, usePMM, useVault, complianceProof, vaultInstructions) =
                abi.decode(extraData, (bytes32, bool, bool, bytes, bytes));
        }

        UniversalCCIPBridge.BridgeOperation memory op = UniversalCCIPBridge.BridgeOperation({
            token: token,
            amount: amount,
            destinationChain: destinationChainSelector,
            recipient: recipientOnDestination,
            assetType: assetType,
            usePMM: usePMM,
            useVault: useVault,
            complianceProof: complianceProof,
            vaultInstructions: vaultInstructions
        });

        messageId = universalBridge.bridge{value: msg.value}(op);
        IERC20(token).forceApprove(address(universalBridge), 0);
    }

    receive() external payable {}
}
