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

import "../ccip/IRouterClient.sol";

/**
 * @title CCIPLogger
 * @notice Receives and logs Chain-138 transactions via Chainlink CCIP
 * @dev Implements replay protection via batch ID tracking; optional authorized signer for future use
 */
contract CCIPLogger {
    IRouterClient public immutable router;
    address public authorizedSigner;
    uint64 public expectedSourceChainSelector;
    address public owner;

    mapping(bytes32 => bool) public processedBatches;

    event RemoteBatchLogged(
        bytes32 indexed messageId,
        bytes32 indexed batchId,
        uint64 sourceChainSelector,
        address sender,
        bytes32[] txHashes,
        address[] froms,
        address[] tos,
        uint256[] values
    );
    event AuthorizedSignerUpdated(address oldSigner, address newSigner);
    event SourceChainSelectorUpdated(uint64 oldSelector, uint64 newSelector);
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    modifier onlyRouter() {
        require(msg.sender == address(router), "CCIPLogger: only router");
        _;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "CCIPLogger: only owner");
        _;
    }

    constructor(
        address _router,
        address _authorizedSigner,
        uint64 _expectedSourceChainSelector
    ) {
        require(_router != address(0), "CCIPLogger: zero router");
        router = IRouterClient(_router);
        authorizedSigner = _authorizedSigner;
        expectedSourceChainSelector = _expectedSourceChainSelector;
        owner = msg.sender;
    }

    /**
     * @notice Handle CCIP message (called by CCIP Router)
     * @param message The received CCIP message
     */
    function ccipReceive(
        IRouterClient.Any2EVMMessage calldata message
    ) external onlyRouter {
        require(
            message.sourceChainSelector == expectedSourceChainSelector,
            "CCIPLogger: invalid source chain"
        );

        (
            bytes32 batchId,
            bytes32[] memory txHashes,
            address[] memory froms,
            address[] memory tos,
            uint256[] memory values,
            bytes memory _extra
        ) = abi.decode(
            message.data,
            (bytes32, bytes32[], address[], address[], uint256[], bytes)
        );

        require(!processedBatches[batchId], "CCIPLogger: batch already processed");
        processedBatches[batchId] = true;

        address sender = message.sender.length >= 20
            ? address(bytes20(message.sender))
            : address(0);
        if (message.sender.length == 32) {
            sender = address(bytes20(message.sender));
        }

        emit RemoteBatchLogged(
            message.messageId,
            batchId,
            message.sourceChainSelector,
            sender,
            txHashes,
            froms,
            tos,
            values
        );
    }

    function getRouter() external view returns (address) {
        return address(router);
    }

    function setAuthorizedSigner(address _signer) external onlyOwner {
        address old = authorizedSigner;
        authorizedSigner = _signer;
        emit AuthorizedSignerUpdated(old, _signer);
    }

    function setExpectedSourceChainSelector(uint64 _selector) external onlyOwner {
        uint64 old = expectedSourceChainSelector;
        expectedSourceChainSelector = _selector;
        emit SourceChainSelectorUpdated(old, _selector);
    }

    function transferOwnership(address newOwner) external onlyOwner {
        require(newOwner != address(0), "CCIPLogger: zero address");
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }
}
