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

import "../ccip/IRouterClient.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";

/**
 * @title CCIP Relay Bridge (LINK)
 * @notice Accepts relayed CCIP messages carrying canonical LINK on the destination chain.
 * @dev Companion to CCIPRelayBridge (WETH9-only). Grant ROUTER_ROLE to the same CCIPRelayRouter.
 */
contract CCIPRelayBridgeLINK is AccessControl {
    bytes32 public constant ROUTER_ROLE = keccak256("ROUTER_ROLE");

    address public immutable link;
    address public relayRouter;

    mapping(bytes32 => bool) public processedTransfers;

    event CrossChainTransferCompleted(
        bytes32 indexed messageId,
        uint64 indexed sourceChainSelector,
        address indexed recipient,
        uint256 amount
    );

    constructor(address _link, address _relayRouter) {
        require(_link != address(0), "CCIPRelayBridgeLINK: zero LINK");
        require(_relayRouter != address(0), "CCIPRelayBridgeLINK: zero router");
        link = _link;
        relayRouter = _relayRouter;
        _grantRole(ROUTER_ROLE, _relayRouter);
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
    }

    function updateRelayRouter(address newRelayRouter) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(newRelayRouter != address(0), "CCIPRelayBridgeLINK: zero address");
        _revokeRole(ROUTER_ROLE, relayRouter);
        relayRouter = newRelayRouter;
        _grantRole(ROUTER_ROLE, newRelayRouter);
    }

    function ccipReceive(IRouterClient.Any2EVMMessage calldata message) external onlyRole(ROUTER_ROLE) {
        require(!processedTransfers[message.messageId], "CCIPRelayBridgeLINK: already processed");
        processedTransfers[message.messageId] = true;

        require(message.tokenAmounts.length > 0, "CCIPRelayBridgeLINK: no tokens");
        require(message.tokenAmounts[0].token == link, "CCIPRelayBridgeLINK: invalid token");

        uint256 amount = message.tokenAmounts[0].amount;
        require(amount > 0, "CCIPRelayBridgeLINK: invalid amount");

        address recipient;
        if (message.data.length == 64) {
            (recipient, ) = abi.decode(message.data, (address, uint256));
        } else if (message.data.length >= 128) {
            (recipient, , , ) = abi.decode(message.data, (address, uint256, address, uint256));
        } else {
            revert("CCIPRelayBridgeLINK: invalid data");
        }
        require(recipient != address(0), "CCIPRelayBridgeLINK: zero recipient");

        require(IERC20(link).transfer(recipient, amount), "CCIPRelayBridgeLINK: transfer failed");

        emit CrossChainTransferCompleted(message.messageId, message.sourceChainSelector, recipient, amount);
    }
}
