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

/**
 * @title ISO4217WCompliance
 * @notice Compliance library for ISO-4217 W tokens
 * @dev Enforces hard constraints: m=1.0, GRU isolation, reserve constraints
 * 
 * MANDATORY CONSTRAINTS:
 * - Classification: M1 eMoney (NOT legal tender, NOT synthetic, NOT commodity-backed)
 * - Money Multiplier: m = 1.0 (hard-fixed, no fractional reserve)
 * - Backing: 1:1 with fiat currency in segregated custodial accounts
 * - GRU Isolation: Direct or indirect GRU conversion prohibited
 */
library ISO4217WCompliance {
    /**
     * @notice Money multiplier constant (hard-fixed at 1.0)
     * @dev MANDATORY: m = 1.0 (no fractional reserve)
     */
    uint256 public constant MONEY_MULTIPLIER = 1e18; // 1.0 in 18 decimals
    uint256 public constant BASIS_POINTS = 10000;
    
    /**
     * @notice Validate money multiplier = 1.0
     * @dev Hard constraint: m MUST equal 1.0
     * @param reserve Reserve balance
     * @param supply Token supply
     * @return isValid True if reserve >= supply (enforcing m = 1.0)
     * @return reasonCode Reason if invalid
     */
    function validateMoneyMultiplier(uint256 reserve, uint256 supply) internal pure returns (
        bool isValid,
        bytes32 reasonCode
    ) {
        // Money multiplier m = 1.0 means: reserve >= supply (exactly 1:1 or better)
        if (reserve < supply) {
            return (false, keccak256("RESERVE_INSUFFICIENT"));
        }
        
        // Allow reserve >= supply (1:1 or better backing)
        // Reject any logic that implies m > 1.0 (fractional reserve)
        return (true, bytes32(0));
    }
    
    /**
     * @notice Validate reserve sufficiency for minting
     * @dev MANDATORY: verifiedReserve >= totalSupply + amount (enforces 1:1 backing)
     * @param currentReserve Current verified reserve
     * @param currentSupply Current token supply
     * @param mintAmount Amount to mint
     * @return isValid True if reserve is sufficient
     * @return reasonCode Reason if invalid
     */
    function validateReserveForMint(
        uint256 currentReserve,
        uint256 currentSupply,
        uint256 mintAmount
    ) internal pure returns (bool isValid, bytes32 reasonCode) {
        uint256 newSupply = currentSupply + mintAmount;
        
        // Constraint: verifiedReserve >= totalSupply + amount
        if (currentReserve < newSupply) {
            return (false, keccak256("RESERVE_INSUFFICIENT_FOR_MINT"));
        }
        
        return (true, bytes32(0));
    }
    
    /**
     * @notice Check if currency code violates GRU isolation
     * @dev GRU identifiers are protocol-blacklisted
     * @param currencyCode Currency code to check
     * @return violatesIsolation True if GRU linkage detected
     */
    function violatesGRUIsolation(string memory currencyCode) internal pure returns (bool violatesIsolation) {
        bytes32 codeHash = keccak256(bytes(currencyCode));
        
        // Blacklist GRU identifiers
        return codeHash == keccak256("GRU") ||
               codeHash == keccak256("M00") ||
               codeHash == keccak256("M0") ||
               codeHash == keccak256("M1");
    }
    
    /**
     * @notice Validate ISO-4217 currency code format
     * @dev ISO-4217 codes are exactly 3 uppercase letters
     * @param currencyCode Currency code to validate
     * @return isValid True if valid ISO-4217 format
     */
    function isValidISO4217Format(string memory currencyCode) internal pure returns (bool isValid) {
        bytes memory codeBytes = bytes(currencyCode);
        if (codeBytes.length != 3) {
            return false;
        }
        
        for (uint256 i = 0; i < 3; i++) {
            uint8 char = uint8(codeBytes[i]);
            if (char < 65 || char > 90) { // Not A-Z
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * @notice Validate token symbol matches <CCC>W pattern
     * @dev Token symbol MUST be <ISO-4217>W (e.g., USDW, EURW)
     * @param currencyCode ISO-4217 currency code
     * @param tokenSymbol Token symbol
     * @return isValid True if symbol matches pattern
     */
    function validateTokenSymbol(string memory currencyCode, string memory tokenSymbol) internal pure returns (bool isValid) {
        // Check if tokenSymbol is currencyCode + "W"
        string memory expectedSymbol = string(abi.encodePacked(currencyCode, "W"));
        return keccak256(bytes(tokenSymbol)) == keccak256(bytes(expectedSymbol));
    }
    
    /**
     * @notice Check if reserve is sufficient
     * @dev Reserve MUST be >= supply (enforcing 1:1 backing)
     * @param reserve Reserve balance
     * @param supply Token supply
     * @return isSufficient True if reserve >= supply
     */
    function isReserveSufficient(uint256 reserve, uint256 supply) internal pure returns (bool isSufficient) {
        return reserve >= supply;
    }
    
    /**
     * @notice Calculate money multiplier (should always be 1.0)
     * @dev For validation/analytics only - MUST NOT influence issuance or pricing
     * @param reserve Reserve balance
     * @param supply Token supply
     * @return multiplier Money multiplier (should be 1.0 in 18 decimals)
     */
    function calculateMoneyMultiplier(uint256 reserve, uint256 supply) internal pure returns (uint256 multiplier) {
        if (supply == 0) {
            return MONEY_MULTIPLIER; // 1.0
        }
        
        // m = reserve / supply
        // Should be >= 1.0 (1:1 or better backing)
        return (reserve * 1e18) / supply;
    }
    
    /**
     * @notice Require money multiplier = 1.0 (revert if violated)
     * @param reserve Reserve balance
     * @param supply Token supply
     */
    function requireMoneyMultiplier(uint256 reserve, uint256 supply) internal pure {
        require(reserve >= supply, "ISO4217WCompliance: money multiplier violation - reserve < supply");
    }
}
