// 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 "../bridge/integration/ICWReserveVerifier.sol";

interface ICWBurnable {
    function burn(uint256 amount) external;
}

/**
 * @title CWBuybackExecutor
 * @notice Routes fee revenue into cW buybacks; burns purchased tokens or locks in treasury.
 */
contract CWBuybackExecutor is AccessControl, ReentrancyGuard {
    using SafeERC20 for IERC20;

    bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE");

    ICWReserveVerifier public reserveVerifier;
    address public treasuryLock;
    bool public burnOnBuyback = true;

    event ReserveVerifierUpdated(address indexed verifier);
    event TreasuryLockUpdated(address indexed treasuryLock);
    event BurnModeUpdated(bool burnOnBuyback);
    event BuybackExecuted(address indexed paymentToken, address indexed cwToken, uint256 paid, uint256 received, bool burned);

    error ZeroAddress();
    error ReserveCheckFailed();

    constructor(address admin, address reserveVerifier_, address treasuryLock_) {
        if (admin == address(0)) {
            revert ZeroAddress();
        }
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(EXECUTOR_ROLE, admin);
        reserveVerifier = ICWReserveVerifier(reserveVerifier_);
        treasuryLock = treasuryLock_;
    }

    function setReserveVerifier(address verifier_) external onlyRole(DEFAULT_ADMIN_ROLE) {
        reserveVerifier = ICWReserveVerifier(verifier_);
        emit ReserveVerifierUpdated(verifier_);
    }

    function setTreasuryLock(address treasuryLock_) external onlyRole(DEFAULT_ADMIN_ROLE) {
        treasuryLock = treasuryLock_;
        emit TreasuryLockUpdated(treasuryLock_);
    }

    function setBurnOnBuyback(bool enabled) external onlyRole(DEFAULT_ADMIN_ROLE) {
        burnOnBuyback = enabled;
        emit BurnModeUpdated(enabled);
    }

    /**
     * @notice Operator delivers pre-purchased cW tokens; contract burns or locks them after reserve check.
     */
    function executeBuyback(
        address canonicalToken,
        uint64 destinationChainSelector,
        address cwToken,
        address paymentToken,
        uint256 paymentAmount,
        uint256 cwAmount
    ) external onlyRole(EXECUTOR_ROLE) nonReentrant {
        if (address(reserveVerifier) != address(0)) {
            if (!reserveVerifier.verifyLock(canonicalToken, destinationChainSelector, 0)) {
                revert ReserveCheckFailed();
            }
        }

        if (paymentAmount > 0 && paymentToken != address(0)) {
            IERC20(paymentToken).safeTransferFrom(msg.sender, address(this), paymentAmount);
        }

        IERC20(cwToken).safeTransferFrom(msg.sender, address(this), cwAmount);

        bool burned = false;
        if (burnOnBuyback) {
            ICWBurnable(cwToken).burn(cwAmount);
            burned = true;
        } else if (treasuryLock != address(0)) {
            IERC20(cwToken).safeTransfer(treasuryLock, cwAmount);
        }

        emit BuybackExecuted(paymentToken, cwToken, paymentAmount, cwAmount, burned);
    }
}
