// 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 "../../interfaces/IAlltraTransport.sol";
import "../../UniversalCCIPBridge.sol";

/**
 * @title AlltraAdapter
 * @notice Bridge adapter for ALL Mainnet (EVM-compatible)
 * @dev ALL Mainnet (651940) is not supported by CCIP. Use setAlltraTransport() to set
 *      AlltraCustomBridge (or other IAlltraTransport) for 138 <-> 651940 flows.
 * @dev Chain ID: 651940 (0x9f2a4) - https://chainlist.org/chain/651940
 */
contract AlltraAdapter is IChainAdapter, AccessControl, ReentrancyGuard {
    using SafeERC20 for IERC20;

    bytes32 public constant BRIDGE_OPERATOR_ROLE = keccak256("BRIDGE_OPERATOR_ROLE");
    
    // ALL Mainnet Chain ID - confirmed from ChainList
    uint256 public constant ALLTRA_MAINNET = 651940;
    
    UniversalCCIPBridge public universalBridge;
    IAlltraTransport public alltraTransport; // When set, used for 651940 instead of CCIP
    bool public isActive;
    /// @notice Configurable bridge fee (default 0.001 ALL). Set via setBridgeFee() after deployment.
    uint256 public bridgeFee;
    
    mapping(bytes32 => BridgeRequest) public bridgeRequests;
    mapping(address => uint256) public nonces;

    event AlltraBridgeInitiated(
        bytes32 indexed requestId,
        address indexed sender,
        address indexed token,
        uint256 amount,
        address recipient
    );
    
    event AlltraBridgeConfirmed(
        bytes32 indexed requestId,
        bytes32 indexed alltraTxHash
    );

    constructor(address admin, address _bridge) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(BRIDGE_OPERATOR_ROLE, admin);
        universalBridge = UniversalCCIPBridge(payable(_bridge));
        isActive = true;
        bridgeFee = 1000000000000000; // 0.001 ALL default; update via setBridgeFee() per ALL Mainnet fee structure
    }

    /**
     * @notice Set custom transport for 138 <-> 651940 (no CCIP). When set, bridge() uses this instead of UniversalCCIPBridge.
     */
    function setAlltraTransport(address _transport) external onlyRole(DEFAULT_ADMIN_ROLE) {
        alltraTransport = IAlltraTransport(_transport);
    }

    function getChainType() external pure override returns (string memory) {
        return "EVM";  // Generic chain type to distinguish from ALLTRA (orchestration layer)
    }

    function getChainIdentifier() external pure override returns (uint256 chainId, string memory identifier) {
        return (ALLTRA_MAINNET, "ALL-Mainnet");  // Updated identifier
    }

    function validateDestination(bytes calldata destination) external pure override returns (bool) {
        // Standard EVM address validation
        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));
        
        // Generate request ID
        requestId = keccak256(abi.encodePacked(
            msg.sender,
            token,
            amount,
            recipientAddr,
            nonces[msg.sender]++,
            block.timestamp
        ));
        
        // Lock tokens
        if (token == address(0)) {
            require(msg.value >= amount, "Insufficient ETH");
        } else {
            IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
        }
        
        // Create bridge request
        bridgeRequests[requestId] = BridgeRequest({
            sender: msg.sender,
            token: token,
            amount: amount,
            destinationData: destination,
            requestId: requestId,
            status: BridgeStatus.Locked,
            createdAt: block.timestamp,
            completedAt: 0
        });
        
        // ALL Mainnet (651940) is not supported by CCIP. Use custom transport when set.
        if (address(alltraTransport) != address(0) && alltraTransport.isConfigured()) {
            alltraTransport.lockAndRelay{value: msg.value}(token, amount, recipientAddr);
        } else {
            // Fallback to UniversalCCIPBridge only if destination were CCIP-supported; 651940 is not.
            revert("AlltraAdapter: set AlltraCustomBridge via setAlltraTransport for 651940");
        }
        
        emit AlltraBridgeInitiated(requestId, msg.sender, token, amount, 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");
        
        // Refund tokens
        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;
    }

    /// @notice Returns the current bridge fee (configurable via setBridgeFee).
    /// @param token Unused; fee is global per adapter.
    /// @param amount Unused.
    /// @param destination Unused.
    /// @return fee Current bridgeFee in wei.
    function estimateFee(
        address token,
        uint256 amount,
        bytes calldata destination
    ) external view override returns (uint256 fee) {
        return bridgeFee;
    }

    /// @notice Update bridge fee. Call after deployment when ALL Mainnet fee structure is known.
    function setBridgeFee(uint256 _fee) external onlyRole(DEFAULT_ADMIN_ROLE) {
        bridgeFee = _fee;
    }

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

    function confirmBridge(bytes32 requestId, bytes32 alltraTxHash) 
        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 AlltraBridgeConfirmed(requestId, alltraTxHash);
    }
}
