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

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "../interfaces/IBurnController.sol";
import "../interfaces/IISO4217WToken.sol";

/**
 * @title BurnController
 * @notice Controls burning of ISO-4217 W tokens on redemption
 * @dev Burn-before-release sequence for on-demand redemption at par
 */
contract BurnController is IBurnController, AccessControl, ReentrancyGuard {
    bytes32 public constant REDEEMER_ROLE = keccak256("REDEEMER_ROLE");
    bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");

    uint256 private _redemptionCounter;

    mapping(address => bool) public isApprovedToken;
    mapping(bytes32 => Redemption) public redemptions;

    struct Redemption {
        address token;
        address redeemer;
        uint256 amount;
        uint256 timestamp;
        bool processed;
    }

    constructor(address admin) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(REDEEMER_ROLE, admin);
        _grantRole(BURNER_ROLE, admin);
    }

    /**
     * @notice Redeem tokens (burn and release fiat)
     * @param token Token address
     * @param from Redeemer address
     * @param amount Amount to redeem (in token decimals)
     * @return redemptionId Redemption ID for tracking
     */
    function redeem(
        address token,
        address from,
        uint256 amount
    ) external override nonReentrant onlyRole(REDEEMER_ROLE) returns (bytes32 redemptionId) {
        require(isApprovedToken[token], "BurnController: token not approved");
        require(amount > 0, "BurnController: zero amount");
        require(from != address(0), "BurnController: zero address");
        
        // Check if redemption is allowed
        require(this.canRedeem(token, amount), "BurnController: redemption not allowed");
        
        // Burn tokens (atomic burn-before-release sequence)
        IISO4217WToken tokenContract = IISO4217WToken(token);
        tokenContract.burn(from, amount);
        
        // Generate redemption ID
        _redemptionCounter++;
        redemptionId = keccak256(abi.encodePacked(token, from, amount, _redemptionCounter, block.timestamp));
        
        // Record redemption
        redemptions[redemptionId] = Redemption({
            token: token,
            redeemer: from,
            amount: amount,
            timestamp: block.timestamp,
            processed: true
        });
        
        // Note: Fiat release happens off-chain or via separate payment system
        // This contract handles the token burn portion
        
        emit Redeemed(token, from, amount, redemptionId);
    }

    /**
     * @notice Burn tokens without redemption (emergency/transfer)
     * @param token Token address
     * @param from Source address
     * @param amount Amount to burn
     */
    function burn(address token, address from, uint256 amount) external override nonReentrant onlyRole(BURNER_ROLE) {
        require(isApprovedToken[token], "BurnController: token not approved");
        require(amount > 0, "BurnController: zero amount");
        
        IISO4217WToken tokenContract = IISO4217WToken(token);
        tokenContract.burn(from, amount);
        
        emit Burned(token, from, amount);
    }

    /**
     * @notice Check if redemption is allowed
     * @param token Token address
     * @param amount Amount to redeem
     * @return redeemable True if redemption is allowed
     */
    function canRedeem(address token, uint256 amount) external view override returns (bool redeemable) {
        if (!isApprovedToken[token]) {
            return false;
        }
        
        IISO4217WToken tokenContract = IISO4217WToken(token);
        uint256 totalSupply = tokenContract.totalSupply();
        
        // Redemption is allowed if supply >= amount
        // Additional checks (e.g., reserve sufficiency) would be added here
        return totalSupply >= amount;
    }

    /**
     * @notice Approve a token for burning/redemption
     * @param token Token address
     */
    function approveToken(address token) external onlyRole(DEFAULT_ADMIN_ROLE) {
        isApprovedToken[token] = true;
    }

    /**
     * @notice Revoke token approval
     * @param token Token address
     */
    function revokeToken(address token) external onlyRole(DEFAULT_ADMIN_ROLE) {
        isApprovedToken[token] = false;
    }

    /**
     * @notice Get redemption information
     * @param redemptionId Redemption ID
     * @return redemption Redemption struct
     */
    function getRedemption(bytes32 redemptionId) external view returns (Redemption memory redemption) {
        return redemptions[redemptionId];
    }
}
