// 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";

/**
 * @title CWStabilityFund
 * @notice Insurance / surplus buffer for bridge, oracle, and temporary depeg events.
 */
contract CWStabilityFund is AccessControl, ReentrancyGuard {
    using SafeERC20 for IERC20;

    bytes32 public constant EMERGENCY_ROLE = keccak256("EMERGENCY_ROLE");
    bytes32 public constant DEPOSITOR_ROLE = keccak256("DEPOSITOR_ROLE");

    mapping(address => bool) public supportedAsset;

    event AssetSupported(address indexed asset, bool supported);
    event Deposited(address indexed asset, address indexed from, uint256 amount);
    event EmergencyWithdrawn(address indexed asset, address indexed to, uint256 amount, bytes32 reason);

    error ZeroAddress();
    error UnsupportedAsset();

    constructor(address admin) {
        if (admin == address(0)) {
            revert ZeroAddress();
        }
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(EMERGENCY_ROLE, admin);
        _grantRole(DEPOSITOR_ROLE, admin);
    }

    function setSupportedAsset(address asset, bool supported) external onlyRole(DEFAULT_ADMIN_ROLE) {
        supportedAsset[asset] = supported;
        emit AssetSupported(asset, supported);
    }

    function deposit(address asset, uint256 amount) external onlyRole(DEPOSITOR_ROLE) nonReentrant {
        if (!supportedAsset[asset]) {
            revert UnsupportedAsset();
        }
        IERC20(asset).safeTransferFrom(msg.sender, address(this), amount);
        emit Deposited(asset, msg.sender, amount);
    }

    function emergencyWithdraw(
        address asset,
        address to,
        uint256 amount,
        bytes32 reason
    ) external onlyRole(EMERGENCY_ROLE) nonReentrant {
        if (to == address(0)) {
            revert ZeroAddress();
        }
        IERC20(asset).safeTransfer(to, amount);
        emit EmergencyWithdrawn(asset, to, amount, reason);
    }

    function balanceOf(address asset) external view returns (uint256) {
        return IERC20(asset).balanceOf(address(this));
    }
}
