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

import "forge-std/Test.sol";
import "../../contracts/registry/UniversalAssetRegistry.sol";
import "../../contracts/bridge/UniversalCCIPBridge.sol";
import "../../contracts/bridge/BridgeOrchestrator.sol";
import "../../contracts/governance/GovernanceController.sol";
import "../../contracts/interfaces/IRegulatedAssetMetadata.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

/// @dev Minimal `IRegulatedAssetMetadata` so `_syncAssetMetadata` ABI-decodes cleanly
/// (Solidity try/catch does not catch return-data decode panics for empty/wrong-length returndata).
contract MockRegulatedAsset is IRegulatedAssetMetadata {
    function assetId() external pure override returns (bytes32) {
        return keccak256("MOCK_ASSET");
    }

    function assetVersionId() external pure override returns (bytes32) {
        return keccak256("MOCK_VER");
    }

    function governanceProfileId() external pure override returns (bytes32) {
        return bytes32(0);
    }

    function supervisionProfileId() external pure override returns (bytes32) {
        return bytes32(0);
    }

    function storageNamespace() external pure override returns (bytes32) {
        return bytes32(0);
    }

    function primaryJurisdiction() external pure override returns (string memory) {
        return "";
    }

    function regulatoryDisclosureURI() external pure override returns (string memory) {
        return "";
    }

    function reportingURI() external pure override returns (string memory) {
        return "";
    }

    function canonicalUnderlyingAsset() external pure override returns (address) {
        return address(0);
    }

    function supervisionRequired() external pure override returns (bool) {
        return false;
    }

    function governmentApprovalRequired() external pure override returns (bool) {
        return false;
    }

    function minimumUpgradeNoticePeriod() external pure override returns (uint256) {
        return 0;
    }

    function wrappedTransport() external pure override returns (bool) {
        return false;
    }
}

/**
 * @title UniversalBridge Integration Tests
 * @notice Comprehensive tests for all asset types through full bridge flow.
 * @dev Uses ERC1967Proxy for upgradeable contracts (registry, governance, bridge, orchestrator).
 */
contract UniversalBridgeTest is Test {
    UniversalAssetRegistry public registry;
    UniversalCCIPBridge public bridge;
    BridgeOrchestrator public orchestrator;
    GovernanceController public governance;
    
    address public admin;
    address public user1;
    address public user2;
    address public mockCCIPRouter;
    
    function setUp() public {
        admin = makeAddr("admin");
        user1 = makeAddr("user1");
        user2 = makeAddr("user2");
        mockCCIPRouter = makeAddr("ccipRouter");
        
        vm.startPrank(admin);
        
        // Deploy upgradeable contracts via proxy (implementations use _disableInitializers())
        UniversalAssetRegistry registryImpl = new UniversalAssetRegistry();
        bytes memory registryInit = abi.encodeCall(UniversalAssetRegistry.initialize, (admin));
        ERC1967Proxy registryProxy = new ERC1967Proxy(address(registryImpl), registryInit);
        registry = UniversalAssetRegistry(address(registryProxy));
        
        GovernanceController governanceImpl = new GovernanceController();
        bytes memory governanceInit = abi.encodeCall(GovernanceController.initialize, (address(registry), admin));
        ERC1967Proxy governanceProxy = new ERC1967Proxy(address(governanceImpl), governanceInit);
        governance = GovernanceController(address(governanceProxy));
        
        UniversalCCIPBridge bridgeImpl = new UniversalCCIPBridge();
        bytes memory bridgeInit = abi.encodeCall(UniversalCCIPBridge.initialize, (address(registry), mockCCIPRouter, admin));
        ERC1967Proxy bridgeProxy = new ERC1967Proxy(address(bridgeImpl), bridgeInit);
        bridge = UniversalCCIPBridge(payable(address(bridgeProxy)));
        
        BridgeOrchestrator orchestratorImpl = new BridgeOrchestrator();
        bytes memory orchestratorInit = abi.encodeCall(BridgeOrchestrator.initialize, (address(registry), address(bridge), admin));
        ERC1967Proxy orchestratorProxy = new ERC1967Proxy(address(orchestratorImpl), orchestratorInit);
        orchestrator = BridgeOrchestrator(address(orchestratorProxy));
        
        vm.stopPrank();
    }

    function testRegisterStandardERC20() public {
        vm.startPrank(admin);
        
        address mockToken = makeAddr("mockToken");
        vm.etch(mockToken, hex"00"); // Give it code
        
        bytes32 proposalId = registry.proposeAsset(
            mockToken,
            UniversalAssetRegistry.AssetType.ERC20Standard,
            UniversalAssetRegistry.ComplianceLevel.Public,
            "Test Token",
            "TEST",
            18,
            "US",
            50, // Medium volatility
            1e15,
            1000000e18
        );
        
        assertTrue(proposalId != bytes32(0), "Proposal should be non-zero");
        
        vm.stopPrank();
    }

    function testGovernanceFlow() public {
        vm.startPrank(admin);
        
        // Add validator
        registry.addValidator(user1);
        
        // Create proposal (real contract: metadata sync ABI-decodes return data; empty etch breaks execute)
        address mockToken = address(new MockRegulatedAsset());

        bytes32 proposalId = registry.proposeAsset(
            mockToken,
            UniversalAssetRegistry.AssetType.Stablecoin,
            UniversalAssetRegistry.ComplianceLevel.Public,
            "Stablecoin",
            "STBL",
            6,
            "US",
            10,
            100e6,
            10000000e6
        );
        
        vm.stopPrank();
        
        // Vote on proposal
        vm.prank(user1);
        registry.voteOnProposal(proposalId, true);
        
        // Fast forward time
        vm.warp(block.timestamp + 2 days);
        
        // Execute proposal
        vm.prank(admin);
        registry.executeProposal(proposalId);
        
        // Verify asset registered
        assertTrue(registry.isAssetActive(mockToken), "Asset should be active");
    }

    function testBridgeExecution() public {
        // Test would bridge a token through the full flow
        // This requires mock CCIP router and token contracts
    }

    function testPMMIntegration() public {
        // Test PMM liquidity provision during bridge
    }

    function testComplianceChecks() public {
        // Test compliance verification for different asset types
    }
}
