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

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "../../interfaces/IChainAdapter.sol";
import "../../UniversalCCIPBridge.sol";

/**
 * @title EVMAdapter
 * @notice Standard bridge adapter for EVM-compatible chains
 * @dev Template adapter for Polygon, Arbitrum, Optimism, Base, Avalanche, BSC, Ethereum
 */
contract EVMAdapter is IChainAdapter, AccessControl, ReentrancyGuard {
    using SafeERC20 for IERC20;

    bytes32 public constant BRIDGE_OPERATOR_ROLE = keccak256("BRIDGE_OPERATOR_ROLE");
    
    uint256 public immutable chainId;
    string public chainName;
    UniversalCCIPBridge public universalBridge;
    bool public isActive;
    
    mapping(bytes32 => BridgeRequest) public bridgeRequests;
    mapping(address => uint256) public nonces;

    event EVMBridgeInitiated(
        bytes32 indexed requestId,
        address indexed sender,
        address indexed token,
        uint256 amount,
        uint256 destinationChainId,
        address recipient
    );
    
    event EVMBridgeConfirmed(
        bytes32 indexed requestId,
        bytes32 indexed txHash
    );

    constructor(
        address admin,
        address _bridge,
        uint256 _chainId,
        string memory _chainName
    ) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(BRIDGE_OPERATOR_ROLE, admin);
        universalBridge = UniversalCCIPBridge(payable(_bridge));
        chainId = _chainId;
        chainName = _chainName;
        isActive = true;
    }

    function getChainType() external pure override returns (string memory) {
        return "EVM";
    }

    function getChainIdentifier() external view override returns (uint256, string memory) {
        return (chainId, chainName);
    }

    function validateDestination(bytes calldata destination) external pure override returns (bool) {
        if (destination.length != 20) return false;
        address dest = address(bytes20(destination));
        return dest != address(0);
    }

    function bridge(
        address token,
        uint256 amount,
        bytes calldata destination,
        bytes calldata recipient
    ) external payable override nonReentrant returns (bytes32 requestId) {
        require(isActive, "Adapter inactive");
        require(amount > 0, "Zero amount");
        require(this.validateDestination(destination), "Invalid destination");
        
        address recipientAddr = address(bytes20(destination));
        
        requestId = keccak256(abi.encodePacked(
            msg.sender,
            token,
            amount,
            recipientAddr,
            chainId,
            nonces[msg.sender]++,
            block.timestamp
        ));
        
        if (token == address(0)) {
            require(msg.value >= amount, "Insufficient ETH");
        } else {
            IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
            IERC20(token).forceApprove(address(universalBridge), amount);
        }

        bridgeRequests[requestId] = BridgeRequest({
            sender: msg.sender,
            token: token,
            amount: amount,
            destinationData: destination,
            requestId: requestId,
            status: BridgeStatus.Locked,
            createdAt: block.timestamp,
            completedAt: 0
        });
        
        UniversalCCIPBridge.BridgeOperation memory op = UniversalCCIPBridge.BridgeOperation({
            token: token,
            amount: amount,
            destinationChain: uint64(chainId),
            recipient: recipientAddr,
            assetType: bytes32(0),
            usePMM: false,
            useVault: false,
            complianceProof: "",
            vaultInstructions: ""
        });
        
        bytes32 messageId = universalBridge.bridge{value: msg.value}(op);
        
        emit EVMBridgeInitiated(requestId, msg.sender, token, amount, chainId, recipientAddr);
        
        return requestId;
    }

    function getBridgeStatus(bytes32 requestId) 
        external view override returns (BridgeRequest memory) {
        return bridgeRequests[requestId];
    }

    function cancelBridge(bytes32 requestId) external override returns (bool) {
        BridgeRequest storage request = bridgeRequests[requestId];
        require(request.status == BridgeStatus.Pending || request.status == BridgeStatus.Locked, "Cannot cancel");
        require(msg.sender == request.sender, "Not request sender");
        
        if (request.token == address(0)) {
            payable(request.sender).transfer(request.amount);
        } else {
            IERC20(request.token).safeTransfer(request.sender, request.amount);
        }
        
        request.status = BridgeStatus.Cancelled;
        return true;
    }

    function estimateFee(
        address token,
        uint256 amount,
        bytes calldata destination
    ) external view override returns (uint256 fee) {
        return 1000000000000000;
    }

    function setIsActive(bool _isActive) external onlyRole(DEFAULT_ADMIN_ROLE) {
        isActive = _isActive;
    }

    function confirmBridge(bytes32 requestId, bytes32 txHash) 
        external onlyRole(BRIDGE_OPERATOR_ROLE) {
        BridgeRequest storage request = bridgeRequests[requestId];
        require(request.status == BridgeStatus.Locked, "Invalid status");
        
        request.status = BridgeStatus.Confirmed;
        request.completedAt = block.timestamp;
        
        emit EVMBridgeConfirmed(requestId, txHash);
    }
}
