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

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./IRWATokenFactory.sol";
import "./RWAToken.sol";
import "./IRWATokenRegistry.sol";
import "./libraries/RWATaxonomy.sol";
import "./IUniversalAssetRegistryRWA.sol";

/**
 * @title RWATokenFactory
 * @notice Canonical factory for Li* M00 commodity index tokens (RWA indices, not c* eMoney).
 * @dev One active deployment per indexTicker per chain. Taxonomy aligned with
 *      config/rwa-capital-markets-taxonomy.v1.json (off-chain source of product metadata).
 */
contract RWATokenFactory is AccessControl, ReentrancyGuard, IRWATokenFactory {
    bytes32 public constant DEPLOYER_ROLE = keccak256("DEPLOYER_ROLE");

    IRWATokenRegistry private immutable _rwaTokenRegistry;
    address private immutable _universalAssetRegistry;

    constructor(
        address admin,
        address rwaTokenRegistry_,
        address universalAssetRegistry_
    ) {
        require(rwaTokenRegistry_ != address(0), "RWATokenFactory: registry");
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(DEPLOYER_ROLE, admin);
        _rwaTokenRegistry = IRWATokenRegistry(rwaTokenRegistry_);
        _universalAssetRegistry = universalAssetRegistry_;
    }

    function rwaTokenRegistry() external view returns (address) {
        return address(_rwaTokenRegistry);
    }

    function universalAssetRegistry() external view returns (address) {
        return _universalAssetRegistry;
    }

    function deployRWAIndex(RWAProductConfig calldata config)
        external
        onlyRole(DEPLOYER_ROLE)
        nonReentrant
        returns (address token)
    {
        RWATaxonomy.validateProduct(config.indexTicker, config.assetClass, config.gruLayer);
        require(
            !_rwaTokenRegistry.isRegistered(config.indexTicker),
            "RWATokenFactory: already registered"
        );
        require(config.initialOwner != address(0), "RWATokenFactory: owner");
        require(config.complianceAdmin != address(0), "RWATokenFactory: compliance");
        require(config.indexPublisher != address(0), "RWATokenFactory: publisher");
        require(config.methodologyDocumentHash != bytes32(0), "RWATokenFactory: methodology");

        RWAToken deployed = new RWAToken(
            config.name,
            config.symbol,
            config.decimals,
            config.indexTicker,
            config.assetClass,
            config.assetGroup,
            config.instrumentType,
            config.underlyingAsset,
            config.gruLayer,
            config.initialOwner,
            config.complianceAdmin,
            config.indexPublisher,
            config.initialIndexValue,
            config.initialSupply,
            config.methodologyDocumentHash
        );
        token = address(deployed);

        _rwaTokenRegistry.registerIndex(config.indexTicker, token, config.symbol);

        if (config.registerInUniversalAssetRegistry && _universalAssetRegistry != address(0)) {
            IUniversalAssetRegistryRWA(_universalAssetRegistry).registerRWAIndexAsset(
                token,
                config.name,
                config.symbol,
                config.decimals,
                config.jurisdiction
            );
        }

        emit RWAIndexDeployed(config.indexTicker, token, config.symbol, config.initialOwner);
    }
}
