// 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/ICollateralAdapter.sol";
import "../interfaces/ILedger.sol";

/**
 * @title CollateralAdapter
 * @notice Handles M0 collateral deposits and withdrawals
 * @dev Only callable by Vaults, only accepts approved assets
 */
contract CollateralAdapter is ICollateralAdapter, AccessControl, ReentrancyGuard {
    using SafeERC20 for IERC20;

    bytes32 public constant VAULT_ROLE = keccak256("VAULT_ROLE");
    bytes32 public constant LIQUIDATOR_ROLE = keccak256("LIQUIDATOR_ROLE");

    ILedger public ledger;
    mapping(address => bool) public approvedAssets;

    constructor(address admin, address ledger_) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        ledger = ILedger(ledger_);
    }

    /**
     * @notice Deposit M0 collateral
     * @param vault Vault address
     * @param asset Collateral asset address (address(0) for native ETH)
     * @param amount Amount to deposit
     */
    function deposit(address vault, address asset, uint256 amount) external payable override nonReentrant onlyRole(VAULT_ROLE) {
        require(approvedAssets[asset] || asset == address(0), "CollateralAdapter: asset not approved");
        require(amount > 0, "CollateralAdapter: zero amount");

        if (asset == address(0)) {
            // Native ETH deposit
            require(msg.value == amount, "CollateralAdapter: value mismatch");
            // ETH is held by this contract
        } else {
            // ERC20 token deposit
            require(msg.value == 0, "CollateralAdapter: unexpected ETH");
            IERC20(asset).safeTransferFrom(msg.sender, address(this), amount);
        }

        // Update ledger
        ledger.modifyCollateral(vault, asset, int256(amount));

        emit CollateralDeposited(vault, asset, amount);
    }

    /**
     * @notice Withdraw M0 collateral
     * @param vault Vault address
     * @param asset Collateral asset address
     * @param amount Amount to withdraw
     */
    function withdraw(address vault, address asset, uint256 amount) external override nonReentrant onlyRole(VAULT_ROLE) {
        require(amount > 0, "CollateralAdapter: zero amount");

        // Update ledger (will revert if insufficient collateral)
        ledger.modifyCollateral(vault, asset, -int256(amount));

        if (asset == address(0)) {
            // Native ETH withdrawal
            (bool success, ) = payable(vault).call{value: amount}("");
            require(success, "CollateralAdapter: ETH transfer failed");
        } else {
            // ERC20 token withdrawal
            IERC20(asset).safeTransfer(vault, amount);
        }

        emit CollateralWithdrawn(vault, asset, amount);
    }

    /**
     * @notice Seize collateral during liquidation
     * @param vault Vault address
     * @param asset Collateral asset address
     * @param amount Amount to seize
     * @param liquidator Liquidator address
     */
    function seize(address vault, address asset, uint256 amount, address liquidator) external override nonReentrant onlyRole(LIQUIDATOR_ROLE) {
        require(amount > 0, "CollateralAdapter: zero amount");
        require(liquidator != address(0), "CollateralAdapter: zero liquidator");

        // Update ledger
        ledger.modifyCollateral(vault, asset, -int256(amount));

        if (asset == address(0)) {
            // Native ETH seizure
            (bool success, ) = payable(liquidator).call{value: amount}("");
            require(success, "CollateralAdapter: ETH transfer failed");
        } else {
            // ERC20 token seizure
            IERC20(asset).safeTransfer(liquidator, amount);
        }

        emit CollateralSeized(vault, asset, amount, liquidator);
    }

    /**
     * @notice Approve an asset for collateral
     * @param asset Asset address
     */
    function approveAsset(address asset) external onlyRole(DEFAULT_ADMIN_ROLE) {
        approvedAssets[asset] = true;
    }

    /**
     * @notice Revoke asset approval
     * @param asset Asset address
     */
    function revokeAsset(address asset) external onlyRole(DEFAULT_ADMIN_ROLE) {
        approvedAssets[asset] = false;
    }

    /**
     * @notice Set ledger address
     * @param ledger_ New ledger address
     */
    function setLedger(address ledger_) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(ledger_ != address(0), "CollateralAdapter: zero address");
        ledger = ILedger(ledger_);
    }

    // Allow contract to receive ETH
    receive() external payable {}
}
