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

import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "../../vendor/openzeppelin/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../../emoney/interfaces/IeMoneyToken.sol";

/**
 * @title DebtToken
 * @notice Token representing outstanding debt obligation (dToken equivalent)
 * @dev Minted when borrow occurs, burned on repayment
 * Interest-accruing, non-freely transferable
 * Extends eMoneyToken pattern
 */
contract DebtToken is Initializable, ERC20Upgradeable, AccessControlUpgradeable, UUPSUpgradeable {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");

    address public vault;
    address public currency; // eMoney currency address
    uint8 private _decimalsStorage;
    bool private _transferable;

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /**
     * @notice Initialize the debt token (5-arg for backward compatibility; decimals=18, not transferable)
     */
    function initialize(
        string memory name,
        string memory symbol,
        address vault_,
        address currency_,
        address admin
    ) external initializer {
        _initializeFull(name, symbol, vault_, currency_, admin, 18, false);
    }

    /**
     * @notice Initialize with decimals and transferability (ERC-20; optionally DEX-transferable)
     * @param decimals_ Token decimals (e.g. 6 for stablecoins; 0 = use 18)
     * @param transferable_ If true, full ERC-20 transfers allowed (DEX-ready)
     */
    function initializeFull(
        string memory name,
        string memory symbol,
        address vault_,
        address currency_,
        address admin,
        uint8 decimals_,
        bool transferable_
    ) external initializer {
        _initializeFull(name, symbol, vault_, currency_, admin, decimals_ > 0 ? decimals_ : 18, transferable_);
    }

    function _initializeFull(
        string memory name,
        string memory symbol,
        address vault_,
        address currency_,
        address admin,
        uint8 decimals_,
        bool transferable_
    ) internal {
        __ERC20_init(name, symbol);
        __AccessControl_init();
        __UUPSUpgradeable_init();
        vault = vault_;
        currency = currency_;
        _decimalsStorage = decimals_;
        _transferable = transferable_;
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
    }

    /**
     * @notice Returns token decimals (matches underlying for DEX compatibility)
     */
    function decimals() public view override returns (uint8) {
        return _decimalsStorage;
    }

    function isTransferable() external view returns (bool) {
        return _transferable;
    }

    /**
     * @notice Mint debt tokens (only by vault)
     * @param to Recipient address
     * @param amount Amount to mint
     */
    function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
        _mint(to, amount);
    }

    /**
     * @notice Burn debt tokens (only by vault)
     * @param from Source address
     * @param amount Amount to burn
     */
    function burn(address from, uint256 amount) external onlyRole(BURNER_ROLE) {
        _burn(from, amount);
    }

    /**
     * @notice Override transfer: when transferable, full ERC-20; else mint/burn/vault only
     */
    function _update(address from, address to, uint256 amount) internal virtual override {
        if (from == address(0) || to == address(0)) {
            super._update(from, to, amount);
            return;
        }
        if (_transferable) {
            super._update(from, to, amount);
            return;
        }
        if (from == vault || to == vault) {
            super._update(from, to, amount);
            return;
        }
        revert("DebtToken: transfers not allowed");
    }

    /**
     * @notice Authorize upgrade (UUPS)
     */
    function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) {}
}
