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

import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "../vendor/openzeppelin/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../vendor/openzeppelin/ReentrancyGuardUpgradeable.sol";
import "../interfaces/IRegulatedAssetMetadata.sol";

/**
 * @title UniversalAssetRegistry
 * @notice Central registry for all asset types with governance and compliance
 * @dev Supports 10+ asset types with hybrid governance based on risk levels
 */
contract UniversalAssetRegistry is 
    Initializable,
    AccessControlUpgradeable,
    ReentrancyGuardUpgradeable,
    UUPSUpgradeable
{
    bytes32 public constant REGISTRAR_ROLE = keccak256("REGISTRAR_ROLE");
    bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE");
    bytes32 public constant VALIDATOR_ROLE = keccak256("VALIDATOR_ROLE");
    bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");
    bytes32 public constant JURISDICTION_MANAGER_ROLE = keccak256("JURISDICTION_MANAGER_ROLE");
    bytes32 public constant REGULATOR_ROLE = keccak256("REGULATOR_ROLE");
    bytes32 public constant SUPERVISOR_ROLE = keccak256("SUPERVISOR_ROLE");
    bytes32 public constant EMERGENCY_ADMIN_ROLE = keccak256("EMERGENCY_ADMIN_ROLE");

    // Asset classification types
    enum AssetType {
        ERC20Standard,      // Standard tokens
        ISO4217W,           // eMoney/CBDCs
        GRU,                // Global Reserve Units (M00/M0/M1)
        Commodity,          // Gold, oil, etc.
        Security,           // Tokenized securities
        RealWorldAsset,     // Real estate, art, etc.
        Synthetic,          // Derivatives, futures
        Stablecoin,         // USDT, USDC, etc.
        GovernanceToken,    // DAO tokens
        NFTBacked           // NFT-collateralized tokens
    }

    // Compliance levels
    enum ComplianceLevel {
        Public,             // No restrictions
        KYC,                // KYC required
        Accredited,         // Accredited investors only
        Institutional,      // Institutions only
        Sovereign           // Central banks/governments only
    }

    // Proposal types
    enum ProposalType {
        AddAsset,
        RemoveAsset,
        UpdateRiskParams,
        UpdateCompliance,
        EmergencyPause
    }

    struct UniversalAsset {
        address tokenAddress;
        AssetType assetType;
        ComplianceLevel complianceLevel;
        
        // Metadata
        string name;
        string symbol;
        uint8 decimals;
        string jurisdiction;
        
        // Risk parameters
        uint8 volatilityScore;      // 0-100
        uint256 minBridgeAmount;
        uint256 maxBridgeAmount;
        uint256 dailyVolumeLimit;
        
        // PMM liquidity
        address pmmPool;
        bool hasLiquidity;
        uint256 liquidityReserveUSD;
        
        // Governance
        bool requiresGovernance;
        address[] validators;
        uint256 validationThreshold;
        
        // Status
        bool isActive;
        uint256 registeredAt;
        uint256 lastUpdated;

        // Governance, storage, and supervision
        bytes32 assetId;
        bytes32 assetVersionId;
        bytes32 governanceProfileId;
        bytes32 supervisionProfileId;
        bytes32 storageNamespace;
        address canonicalUnderlyingAsset;
        bool isWrappedTransport;
        bool supervisionRequired;
        bool governmentApprovalRequired;
        uint256 minimumUpgradeNoticePeriod;
        string regulatoryDisclosureURI;
        string reportingURI;
    }

    struct PendingAssetProposal {
        bytes32 proposalId;
        ProposalType proposalType;
        address proposer;
        uint256 proposedAt;
        uint256 executeAfter;
        uint256 votesFor;
        uint256 votesAgainst;
        bool executed;
        bool cancelled;
        
        // Proposal data
        address tokenAddress;
        AssetType assetType;
        ComplianceLevel complianceLevel;
        string name;
        string symbol;
        uint8 decimals;
        string jurisdiction;
        uint8 volatilityScore;
        uint256 minBridgeAmount;
        uint256 maxBridgeAmount;
    }

    struct JurisdictionProfile {
        bool active;
        bool requiresGovernmentApproval;
        bool requiresPeriodicReports;
        uint256 minimumUpgradeNoticePeriod;
        string supervisionURI;
        bytes32 policyHash;
    }

    struct JurisdictionAuthority {
        bool active;
        bool canApproveGovernance;
        bool canApproveUpgrades;
        bool canPause;
        bool canReceiveReports;
    }

    // Storage
    mapping(address => UniversalAsset) public assets;
    mapping(AssetType => address[]) public assetsByType;
    mapping(bytes32 => PendingAssetProposal) public proposals;
    mapping(bytes32 => mapping(address => bool)) public hasVoted;
    
    // Governance parameters
    uint256 public constant TIMELOCK_STANDARD = 1 days;
    uint256 public constant TIMELOCK_MODERATE = 3 days;
    uint256 public constant TIMELOCK_HIGH = 7 days;
    uint256 public quorumPercentage;
    
    // Validator set
    address[] public validators;
    mapping(address => bool) public isValidator;
    address public governanceController;
    mapping(bytes32 => JurisdictionProfile) private _jurisdictionProfiles;
    mapping(bytes32 => mapping(address => JurisdictionAuthority)) private _jurisdictionAuthorities;
    mapping(address => bytes32) private _assetJurisdictionIds;

    // Events
    event AssetProposed(
        bytes32 indexed proposalId,
        address indexed token,
        AssetType assetType,
        address proposer
    );
    
    event AssetApproved(
        address indexed token,
        AssetType assetType,
        ComplianceLevel complianceLevel
    );
    
    event AssetRemoved(address indexed token, AssetType assetType);
    
    event ValidatorAdded(address indexed validator);
    event ValidatorRemoved(address indexed validator);
    
    event ProposalVoted(
        bytes32 indexed proposalId,
        address indexed voter,
        bool support
    );
    
    event ProposalExecuted(bytes32 indexed proposalId);
    event ProposalCancelled(bytes32 indexed proposalId);
    event JurisdictionProfileUpdated(
        bytes32 indexed jurisdictionId,
        string jurisdiction,
        bool active,
        bool requiresGovernmentApproval,
        bool requiresPeriodicReports,
        uint256 minimumUpgradeNoticePeriod,
        string supervisionURI,
        bytes32 policyHash
    );
    event JurisdictionAuthorityUpdated(
        bytes32 indexed jurisdictionId,
        string jurisdiction,
        address indexed authority,
        bool active,
        bool canApproveGovernance,
        bool canApproveUpgrades,
        bool canPause,
        bool canReceiveReports
    );
    event AssetGovernanceProfileUpdated(
        address indexed token,
        bytes32 governanceProfileId,
        bytes32 supervisionProfileId,
        bytes32 storageNamespace
    );
    event AssetSupervisionProfileUpdated(
        address indexed token,
        address canonicalUnderlyingAsset,
        bool isWrappedTransport,
        bool supervisionRequired,
        bool governmentApprovalRequired,
        uint256 minimumUpgradeNoticePeriod
    );

    error GovernanceControllerOnly(address caller);
    error GovernanceControllerNotConfigured();
    error ZeroGovernanceController();

    modifier onlyGovernanceExecution() {
        if (governanceController == address(0)) revert GovernanceControllerNotConfigured();
        if (_msgSender() != governanceController) revert GovernanceControllerOnly(_msgSender());
        _;
    }

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

    function initialize(address admin) external initializer {
        __AccessControl_init();
        __ReentrancyGuard_init();
        __UUPSUpgradeable_init();
        
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        _grantRole(REGISTRAR_ROLE, admin);
        _grantRole(PROPOSER_ROLE, admin);
        _grantRole(VALIDATOR_ROLE, admin);
        _grantRole(UPGRADER_ROLE, admin);
        _grantRole(JURISDICTION_MANAGER_ROLE, admin);
        _grantRole(REGULATOR_ROLE, admin);
        _grantRole(SUPERVISOR_ROLE, admin);
        _grantRole(EMERGENCY_ADMIN_ROLE, admin);
        
        quorumPercentage = 51; // 51% quorum
    }

    function _authorizeUpgrade(address newImplementation)
        internal override onlyRole(UPGRADER_ROLE) {}

    /**
     * @notice Propose new asset with timelock governance
     */
    function proposeAsset(
        address tokenAddress,
        AssetType assetType,
        ComplianceLevel complianceLevel,
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        string calldata jurisdiction,
        uint8 volatilityScore,
        uint256 minBridge,
        uint256 maxBridge
    ) external onlyRole(PROPOSER_ROLE) returns (bytes32 proposalId) {
        require(tokenAddress != address(0), "Zero address");
        require(!assets[tokenAddress].isActive, "Already registered");
        require(volatilityScore <= 100, "Invalid volatility");
        require(maxBridge >= minBridge, "Invalid limits");
        
        proposalId = keccak256(abi.encode(
            tokenAddress,
            assetType,
            block.timestamp,
            msg.sender
        ));
        
        uint256 timelockPeriod = _getTimelockPeriod(assetType, complianceLevel);
        
        PendingAssetProposal storage proposal = proposals[proposalId];
        proposal.proposalId = proposalId;
        proposal.proposalType = ProposalType.AddAsset;
        proposal.proposer = msg.sender;
        proposal.proposedAt = block.timestamp;
        proposal.executeAfter = block.timestamp + timelockPeriod;
        proposal.tokenAddress = tokenAddress;
        proposal.assetType = assetType;
        proposal.complianceLevel = complianceLevel;
        proposal.name = name;
        proposal.symbol = symbol;
        proposal.decimals = decimals;
        proposal.jurisdiction = jurisdiction;
        proposal.volatilityScore = volatilityScore;
        proposal.minBridgeAmount = minBridge;
        proposal.maxBridgeAmount = maxBridge;
        
        emit AssetProposed(proposalId, tokenAddress, assetType, msg.sender);
        
        return proposalId;
    }

    /**
     * @notice Vote on asset proposal
     */
    function voteOnProposal(
        bytes32 proposalId,
        bool support
    ) external onlyRole(VALIDATOR_ROLE) {
        PendingAssetProposal storage proposal = proposals[proposalId];
        require(!proposal.executed, "Already executed");
        require(!proposal.cancelled, "Cancelled");
        require(!hasVoted[proposalId][msg.sender], "Already voted");
        
        hasVoted[proposalId][msg.sender] = true;
        
        if (support) {
            proposal.votesFor++;
        } else {
            proposal.votesAgainst++;
        }
        
        emit ProposalVoted(proposalId, msg.sender, support);
    }

    /**
     * @notice Execute proposal after timelock
     */
    function executeProposal(bytes32 proposalId) external nonReentrant {
        PendingAssetProposal storage proposal = proposals[proposalId];
        
        require(!proposal.executed, "Already executed");
        require(!proposal.cancelled, "Cancelled");
        require(block.timestamp >= proposal.executeAfter, "Timelock active");
        
        // Check quorum
        uint256 totalVotes = proposal.votesFor + proposal.votesAgainst;
        uint256 requiredVotes = (validators.length * quorumPercentage) / 100;
        require(totalVotes >= requiredVotes, "Quorum not met");
        require(proposal.votesFor > proposal.votesAgainst, "Rejected");
        
        // Execute based on proposal type
        if (proposal.proposalType == ProposalType.AddAsset) {
            _registerAsset(proposal);
        }
        
        proposal.executed = true;
        emit ProposalExecuted(proposalId);
    }

    /**
     * @notice Register a GRU compliant token (c*) directly — no timelock. For use by deploy scripts to integrate all c* with GRU ERC-2535 / bridge.
     * @dev Only REGISTRAR_ROLE. Registers as AssetType.GRU so GRUCCIPBridge and PoolManager accept the token.
     */
    function registerGRUCompliantAsset(
        address tokenAddress,
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        string calldata jurisdiction
    ) external onlyRole(REGISTRAR_ROLE) {
        require(tokenAddress != address(0), "Zero address");
        require(!assets[tokenAddress].isActive, "Already registered");
        _registerAssetDirect(
            tokenAddress,
            AssetType.GRU,
            ComplianceLevel.Institutional,
            name,
            symbol,
            decimals,
            jurisdiction,
            10,      // volatilityScore (low for stable)
            1e6,     // minBridge (1 unit with 6 decimals)
            100_000_000 * 10**6  // maxBridge (100M with 6 decimals)
        );
    }

    /**
     * @notice Register an M00 Li* RWA index token (LiXAU, LiPMG, LiBMG*) — not c* eMoney.
     * @dev Only REGISTRAR_ROLE. AssetType.RealWorldAsset for bridge/routing policy separation from GRU/c*.
     */
    function registerRWAIndexAsset(
        address tokenAddress,
        string calldata name,
        string calldata symbol,
        uint8 decimals,
        string calldata jurisdiction
    ) external onlyRole(REGISTRAR_ROLE) {
        require(tokenAddress != address(0), "Zero address");
        require(!assets[tokenAddress].isActive, "Already registered");
        _registerAssetDirect(
            tokenAddress,
            AssetType.RealWorldAsset,
            ComplianceLevel.Institutional,
            name,
            symbol,
            decimals,
            jurisdiction,
            50,
            1,
            100_000_000 * 10 ** 6
        );
    }

    /**
     * @notice Internal asset registration from proposal
     */
    function _registerAsset(PendingAssetProposal storage proposal) internal {
        _registerAssetDirect(
            proposal.tokenAddress,
            proposal.assetType,
            proposal.complianceLevel,
            proposal.name,
            proposal.symbol,
            proposal.decimals,
            proposal.jurisdiction,
            proposal.volatilityScore,
            proposal.minBridgeAmount,
            proposal.maxBridgeAmount
        );
    }

    /**
     * @notice Internal asset registration (shared by proposal execution and registerGRUCompliantAsset)
     */
    function _registerAssetDirect(
        address tokenAddress,
        AssetType assetType,
        ComplianceLevel complianceLevel,
        string memory name,
        string memory symbol,
        uint8 decimals,
        string memory jurisdiction,
        uint8 volatilityScore,
        uint256 minBridgeAmount,
        uint256 maxBridgeAmount
    ) internal {
        UniversalAsset storage asset = assets[tokenAddress];
        asset.tokenAddress = tokenAddress;
        asset.assetType = assetType;
        asset.complianceLevel = complianceLevel;
        asset.name = name;
        asset.symbol = symbol;
        asset.decimals = decimals;
        asset.jurisdiction = jurisdiction;
        asset.volatilityScore = volatilityScore;
        asset.minBridgeAmount = minBridgeAmount;
        asset.maxBridgeAmount = maxBridgeAmount;
        unchecked {
            asset.dailyVolumeLimit =
                maxBridgeAmount > type(uint256).max / 10 ? type(uint256).max : maxBridgeAmount * 10;
        }
        asset.requiresGovernance = _requiresGovernance(assetType, complianceLevel);
        asset.isActive = true;
        asset.registeredAt = block.timestamp;
        asset.lastUpdated = block.timestamp;
        _assetJurisdictionIds[tokenAddress] = jurisdictionIdFor(jurisdiction);
        _syncAssetMetadata(tokenAddress, asset);
        _applyJurisdictionDefaults(asset, _assetJurisdictionIds[tokenAddress]);
        assetsByType[assetType].push(tokenAddress);
        emit AssetApproved(tokenAddress, assetType, complianceLevel);
    }

    /**
     * @notice Add validator
     */
    function addValidator(address validator) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(validator != address(0), "Zero address");
        require(!isValidator[validator], "Already validator");
        
        validators.push(validator);
        isValidator[validator] = true;
        _grantRole(VALIDATOR_ROLE, validator);
        
        emit ValidatorAdded(validator);
    }

    /**
     * @notice Remove validator
     */
    function removeValidator(address validator) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(isValidator[validator], "Not validator");
        
        isValidator[validator] = false;
        _revokeRole(VALIDATOR_ROLE, validator);
        
        // Remove from array
        for (uint256 i = 0; i < validators.length; i++) {
            if (validators[i] == validator) {
                validators[i] = validators[validators.length - 1];
                validators.pop();
                break;
            }
        }
        
        emit ValidatorRemoved(validator);
    }

    /**
     * @notice Update PMM pool for asset
     */
    function updatePMMPool(
        address token,
        address pmmPool
    ) external onlyRole(REGISTRAR_ROLE) {
        require(assets[token].isActive, "Not registered");
        
        assets[token].pmmPool = pmmPool;
        assets[token].hasLiquidity = pmmPool != address(0);
        assets[token].lastUpdated = block.timestamp;
    }

    function setGovernanceController(address governanceController_) external onlyRole(EMERGENCY_ADMIN_ROLE) {
        if (governanceController_ == address(0)) revert ZeroGovernanceController();
        governanceController = governanceController_;
    }

    function setJurisdictionProfile(
        string calldata jurisdiction,
        bool active,
        bool requiresGovernmentApproval,
        bool requiresPeriodicReports,
        uint256 minimumUpgradeNoticePeriod,
        string calldata supervisionURI,
        bytes32 policyHash
    ) external onlyGovernanceExecution {
        _setJurisdictionProfileValue(
            jurisdiction,
            active,
            requiresGovernmentApproval,
            requiresPeriodicReports,
            minimumUpgradeNoticePeriod,
            supervisionURI,
            policyHash
        );
    }

    function setDerivedJurisdictionProfile(
        address token,
        bool active,
        bool requiresGovernmentApproval,
        bool requiresPeriodicReports,
        uint256 minimumUpgradeNoticePeriod,
        string calldata supervisionURI,
        bytes32 policyHash
    ) external onlyGovernanceExecution {
        require(assets[token].isActive, "Not registered");
        _setJurisdictionProfileValue(
            assets[token].jurisdiction,
            active,
            requiresGovernmentApproval,
            requiresPeriodicReports,
            minimumUpgradeNoticePeriod,
            supervisionURI,
            policyHash
        );
    }

    function emergencySetJurisdictionProfile(
        string calldata jurisdiction,
        bool active,
        bool requiresGovernmentApproval,
        bool requiresPeriodicReports,
        uint256 minimumUpgradeNoticePeriod,
        string calldata supervisionURI,
        bytes32 policyHash
    ) external onlyRole(EMERGENCY_ADMIN_ROLE) {
        _setJurisdictionProfileValue(
            jurisdiction,
            active,
            requiresGovernmentApproval,
            requiresPeriodicReports,
            minimumUpgradeNoticePeriod,
            supervisionURI,
            policyHash
        );
    }

    function _setJurisdictionProfileValue(
        string memory jurisdiction,
        bool active,
        bool requiresGovernmentApproval,
        bool requiresPeriodicReports,
        uint256 minimumUpgradeNoticePeriod,
        string memory supervisionURI,
        bytes32 policyHash
    ) internal {
        bytes32 jurisdictionId = jurisdictionIdFor(jurisdiction);
        JurisdictionProfile storage profile = _jurisdictionProfiles[jurisdictionId];
        profile.active = active;
        profile.requiresGovernmentApproval = requiresGovernmentApproval;
        profile.requiresPeriodicReports = requiresPeriodicReports;
        profile.minimumUpgradeNoticePeriod = minimumUpgradeNoticePeriod;
        profile.supervisionURI = supervisionURI;
        profile.policyHash = policyHash;

        emit JurisdictionProfileUpdated(
            jurisdictionId,
            jurisdiction,
            active,
            requiresGovernmentApproval,
            requiresPeriodicReports,
            minimumUpgradeNoticePeriod,
            supervisionURI,
            policyHash
        );
    }

    function setJurisdictionAuthority(
        string calldata jurisdiction,
        address authority,
        bool active,
        bool canApproveGovernance,
        bool canApproveUpgrades,
        bool canPause,
        bool canReceiveReports
    ) external onlyGovernanceExecution {
        _setJurisdictionAuthorityValue(
            jurisdiction,
            authority,
            active,
            canApproveGovernance,
            canApproveUpgrades,
            canPause,
            canReceiveReports
        );
    }

    function setDerivedJurisdictionAuthority(
        address token,
        address authority,
        bool active,
        bool canApproveGovernance,
        bool canApproveUpgrades,
        bool canPause,
        bool canReceiveReports
    ) external onlyGovernanceExecution {
        require(assets[token].isActive, "Not registered");
        _setJurisdictionAuthorityValue(
            assets[token].jurisdiction,
            authority,
            active,
            canApproveGovernance,
            canApproveUpgrades,
            canPause,
            canReceiveReports
        );
    }

    function emergencySetJurisdictionAuthority(
        string calldata jurisdiction,
        address authority,
        bool active,
        bool canApproveGovernance,
        bool canApproveUpgrades,
        bool canPause,
        bool canReceiveReports
    ) external onlyRole(EMERGENCY_ADMIN_ROLE) {
        _setJurisdictionAuthorityValue(
            jurisdiction,
            authority,
            active,
            canApproveGovernance,
            canApproveUpgrades,
            canPause,
            canReceiveReports
        );
    }

    function _setJurisdictionAuthorityValue(
        string memory jurisdiction,
        address authority,
        bool active,
        bool canApproveGovernance,
        bool canApproveUpgrades,
        bool canPause,
        bool canReceiveReports
    ) internal {
        require(authority != address(0), "Zero address");
        bytes32 jurisdictionId = jurisdictionIdFor(jurisdiction);
        _jurisdictionAuthorities[jurisdictionId][authority] = JurisdictionAuthority({
            active: active,
            canApproveGovernance: canApproveGovernance,
            canApproveUpgrades: canApproveUpgrades,
            canPause: canPause,
            canReceiveReports: canReceiveReports
        });

        emit JurisdictionAuthorityUpdated(
            jurisdictionId,
            jurisdiction,
            authority,
            active,
            canApproveGovernance,
            canApproveUpgrades,
            canPause,
            canReceiveReports
        );
    }

    function setAssetGovernanceProfile(
        address token,
        bytes32 governanceProfileId,
        bytes32 supervisionProfileId,
        bytes32 storageNamespace,
        address canonicalUnderlyingAsset,
        bool isWrappedTransport,
        bool supervisionRequired,
        bool governmentApprovalRequired,
        uint256 minimumUpgradeNoticePeriod,
        string calldata regulatoryDisclosureURI,
        string calldata reportingURI
    ) external onlyGovernanceExecution {
        _setAssetGovernanceProfileValue(
            token,
            governanceProfileId,
            supervisionProfileId,
            storageNamespace,
            canonicalUnderlyingAsset,
            isWrappedTransport,
            supervisionRequired,
            governmentApprovalRequired,
            minimumUpgradeNoticePeriod,
            regulatoryDisclosureURI,
            reportingURI
        );
    }

    function emergencySetAssetGovernanceProfile(
        address token,
        bytes32 governanceProfileId,
        bytes32 supervisionProfileId,
        bytes32 storageNamespace,
        address canonicalUnderlyingAsset,
        bool isWrappedTransport,
        bool supervisionRequired,
        bool governmentApprovalRequired,
        uint256 minimumUpgradeNoticePeriod,
        string calldata regulatoryDisclosureURI,
        string calldata reportingURI
    ) external onlyRole(EMERGENCY_ADMIN_ROLE) {
        _setAssetGovernanceProfileValue(
            token,
            governanceProfileId,
            supervisionProfileId,
            storageNamespace,
            canonicalUnderlyingAsset,
            isWrappedTransport,
            supervisionRequired,
            governmentApprovalRequired,
            minimumUpgradeNoticePeriod,
            regulatoryDisclosureURI,
            reportingURI
        );
    }

    function _setAssetGovernanceProfileValue(
        address token,
        bytes32 governanceProfileId,
        bytes32 supervisionProfileId,
        bytes32 storageNamespace,
        address canonicalUnderlyingAsset,
        bool isWrappedTransport,
        bool supervisionRequired,
        bool governmentApprovalRequired,
        uint256 minimumUpgradeNoticePeriod,
        string memory regulatoryDisclosureURI,
        string memory reportingURI
    ) internal {
        require(assets[token].isActive, "Not registered");

        UniversalAsset storage asset = assets[token];
        asset.governanceProfileId = governanceProfileId;
        asset.supervisionProfileId = supervisionProfileId;
        asset.storageNamespace = storageNamespace;
        asset.canonicalUnderlyingAsset = canonicalUnderlyingAsset;
        asset.isWrappedTransport = isWrappedTransport;
        asset.supervisionRequired = supervisionRequired;
        asset.governmentApprovalRequired = governmentApprovalRequired;
        asset.minimumUpgradeNoticePeriod = minimumUpgradeNoticePeriod;
        asset.regulatoryDisclosureURI = regulatoryDisclosureURI;
        asset.reportingURI = reportingURI;
        asset.lastUpdated = block.timestamp;

        emit AssetGovernanceProfileUpdated(token, governanceProfileId, supervisionProfileId, storageNamespace);
        emit AssetSupervisionProfileUpdated(
            token,
            canonicalUnderlyingAsset,
            isWrappedTransport,
            supervisionRequired,
            governmentApprovalRequired,
            minimumUpgradeNoticePeriod
        );
    }

    function syncAssetMetadataFromToken(address token) external onlyGovernanceExecution {
        require(assets[token].isActive, "Not registered");
        _syncAssetMetadata(token, assets[token]);
        assets[token].lastUpdated = block.timestamp;
    }

    function emergencySyncAssetMetadataFromToken(address token) external onlyRole(EMERGENCY_ADMIN_ROLE) {
        require(assets[token].isActive, "Not registered");
        _syncAssetMetadata(token, assets[token]);
        assets[token].lastUpdated = block.timestamp;
    }

    /**
     * @notice Get timelock period based on asset type and compliance
     */
    function _getTimelockPeriod(
        AssetType assetType,
        ComplianceLevel complianceLevel
    ) internal pure returns (uint256) {
        if (assetType == AssetType.Security ||
            assetType == AssetType.ISO4217W ||
            complianceLevel >= ComplianceLevel.Institutional) {
            return TIMELOCK_HIGH;
        } else if (assetType == AssetType.Commodity ||
                   assetType == AssetType.RealWorldAsset ||
                   complianceLevel >= ComplianceLevel.Accredited) {
            return TIMELOCK_MODERATE;
        } else {
            return TIMELOCK_STANDARD;
        }
    }

    /**
     * @notice Check if asset type requires governance
     */
    function _requiresGovernance(
        AssetType assetType,
        ComplianceLevel complianceLevel
    ) internal pure returns (bool) {
        return assetType == AssetType.Security ||
               assetType == AssetType.ISO4217W ||
               assetType == AssetType.Commodity ||
               complianceLevel >= ComplianceLevel.Accredited;
    }

    // View functions
    
    function getAsset(address token) external view returns (UniversalAsset memory) {
        return assets[token];
    }

    function getAssetType(address token) external view returns (AssetType) {
        return assets[token].assetType;
    }

    function getAssetsByType(AssetType assetType) external view returns (address[] memory) {
        return assetsByType[assetType];
    }

    function getValidators() external view returns (address[] memory) {
        return validators;
    }

    function getJurisdictionProfile(string calldata jurisdiction) external view returns (JurisdictionProfile memory) {
        return _jurisdictionProfiles[jurisdictionIdFor(jurisdiction)];
    }

    function getJurisdictionAuthority(
        string calldata jurisdiction,
        address authority
    ) external view returns (JurisdictionAuthority memory) {
        return _jurisdictionAuthorities[jurisdictionIdFor(jurisdiction)][authority];
    }

    function getAssetJurisdictionId(address token) external view returns (bytes32) {
        return _assetJurisdictionIds[token];
    }

    function isGovernanceAuthority(bytes32 jurisdictionId, address authority) external view returns (bool) {
        JurisdictionAuthority storage permissions = _jurisdictionAuthorities[jurisdictionId][authority];
        return permissions.active && permissions.canApproveGovernance;
    }

    function getJurisdictionMinimumUpgradeNotice(bytes32 jurisdictionId) external view returns (uint256) {
        return _jurisdictionProfiles[jurisdictionId].minimumUpgradeNoticePeriod;
    }

    function getProposal(bytes32 proposalId) external view returns (PendingAssetProposal memory) {
        return proposals[proposalId];
    }

    function isAssetActive(address token) external view returns (bool) {
        return assets[token].isActive;
    }

    function jurisdictionIdFor(string memory jurisdiction) public pure returns (bytes32) {
        return keccak256(bytes(jurisdiction));
    }

    function _applyJurisdictionDefaults(UniversalAsset storage asset, bytes32 jurisdictionId) internal {
        JurisdictionProfile storage profile = _jurisdictionProfiles[jurisdictionId];
        if (!profile.active) {
            return;
        }

        asset.supervisionRequired = true;
        asset.governmentApprovalRequired = profile.requiresGovernmentApproval;
        if (profile.minimumUpgradeNoticePeriod > asset.minimumUpgradeNoticePeriod) {
            asset.minimumUpgradeNoticePeriod = profile.minimumUpgradeNoticePeriod;
        }
    }

    function _syncAssetMetadata(address tokenAddress, UniversalAsset storage asset) internal {
        asset.assetId = _defaultAssetId(asset.symbol);
        asset.assetVersionId = _defaultAssetVersionId(asset.symbol);
        asset.governanceProfileId = _defaultGovernanceProfileId(asset.symbol);
        asset.supervisionProfileId = _defaultSupervisionProfileId(asset.symbol);
        asset.storageNamespace = _defaultStorageNamespace(asset.symbol);

        try IRegulatedAssetMetadata(tokenAddress).assetId() returns (bytes32 value) {
            asset.assetId = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).assetVersionId() returns (bytes32 value) {
            asset.assetVersionId = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).governanceProfileId() returns (bytes32 value) {
            asset.governanceProfileId = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).supervisionProfileId() returns (bytes32 value) {
            asset.supervisionProfileId = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).storageNamespace() returns (bytes32 value) {
            asset.storageNamespace = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).primaryJurisdiction() returns (string memory jurisdictionValue) {
            if (bytes(jurisdictionValue).length > 0) {
                asset.jurisdiction = jurisdictionValue;
                _assetJurisdictionIds[tokenAddress] = jurisdictionIdFor(jurisdictionValue);
            }
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).regulatoryDisclosureURI() returns (string memory value) {
            asset.regulatoryDisclosureURI = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).reportingURI() returns (string memory value) {
            asset.reportingURI = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).canonicalUnderlyingAsset() returns (address value) {
            asset.canonicalUnderlyingAsset = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).supervisionRequired() returns (bool value) {
            asset.supervisionRequired = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).governmentApprovalRequired() returns (bool value) {
            asset.governmentApprovalRequired = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).minimumUpgradeNoticePeriod() returns (uint256 value) {
            asset.minimumUpgradeNoticePeriod = value;
        } catch {}

        try IRegulatedAssetMetadata(tokenAddress).wrappedTransport() returns (bool value) {
            asset.isWrappedTransport = value;
        } catch {}
    }

    function _defaultAssetId(string memory symbol) internal pure returns (bytes32) {
        return keccak256(bytes(string.concat("GRU:", symbol)));
    }

    function _defaultAssetVersionId(string memory symbol) internal pure returns (bytes32) {
        return keccak256(bytes(string.concat("GRU:", symbol, ":registry-v1")));
    }

    function _defaultGovernanceProfileId(string memory symbol) internal pure returns (bytes32) {
        return keccak256(bytes(string.concat("GRU:GOV:", symbol)));
    }

    function _defaultSupervisionProfileId(string memory symbol) internal pure returns (bytes32) {
        return keccak256(bytes(string.concat("GRU:SUP:", symbol)));
    }

    function _defaultStorageNamespace(string memory symbol) internal pure returns (bytes32) {
        return keccak256(bytes(string.concat("gru.storage.registry.", symbol)));
    }
}
