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

import "forge-std/Script.sol";
import "../../../contracts/iso4217w/ComplianceGuard.sol";
import "../../../contracts/iso4217w/oracle/ReserveOracle.sol";
import "../../../contracts/iso4217w/controllers/MintController.sol";
import "../../../contracts/iso4217w/controllers/BurnController.sol";
import "../../../contracts/iso4217w/registry/TokenRegistry.sol";
import "../../../contracts/iso4217w/TokenFactory.sol";
import "../../../contracts/iso4217w/ISO4217WToken.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

/**
 * @title DeployISO4217WSystem
 * @notice Deployment script for the complete ISO-4217W Token System
 * @dev Deploys all ISO-4217W system components and initializes W tokens
 */
contract DeployISO4217WSystem is Script {
    // Deployed contracts
    ComplianceGuard public complianceGuard;
    ReserveOracle public reserveOracle;
    MintController public mintController;
    BurnController public burnController;
    TokenRegistry public tokenRegistry;
    TokenFactory public tokenFactory;

    // W Tokens
    ISO4217WToken public usdw;
    ISO4217WToken public eurw;
    ISO4217WToken public gbpw;
    ISO4217WToken public audw;
    ISO4217WToken public jpyw;
    ISO4217WToken public chfw;
    ISO4217WToken public cadw;

    // Configuration
    address public admin;
    address public custodian;
    address public reserveManager;

    // Reserve Oracle configuration
    address[] public reserveTransmitters;
    uint256 public constant QUORUM_THRESHOLD = 2; // Minimum 2 confirmations
    uint256 public constant STALENESS_THRESHOLD = 3600; // 1 hour

    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        admin = vm.addr(deployerPrivateKey);
        custodian = vm.envOr("CUSTODIAN_ADDRESS", vm.addr(deployerPrivateKey));
        reserveManager = vm.envOr("RESERVE_MANAGER_ADDRESS", vm.addr(deployerPrivateKey));

        // Reserve transmitters (oracle nodes)
        reserveTransmitters.push(vm.envOr("RESERVE_TRANSMITTER_1", vm.addr(deployerPrivateKey)));
        reserveTransmitters.push(vm.envOr("RESERVE_TRANSMITTER_2", vm.addr(deployerPrivateKey)));

        vm.startBroadcast(deployerPrivateKey);

        console.log("=== Deploying ISO-4217W Token System ===");
        console.log("Admin:", admin);
        console.log("Custodian:", custodian);
        console.log("Reserve Manager:", reserveManager);

        // Step 1: Deploy Compliance Guard
        console.log("\n1. Deploying Compliance Guard...");
        complianceGuard = new ComplianceGuard(admin);
        console.log("Compliance Guard:", address(complianceGuard));

        // Step 2: Deploy Reserve Oracle
        console.log("\n2. Deploying Reserve Oracle...");
        reserveOracle = new ReserveOracle(admin, QUORUM_THRESHOLD, STALENESS_THRESHOLD);
        
        // Add reserve oracles (transmitters)
        for (uint256 i = 0; i < reserveTransmitters.length; i++) {
            reserveOracle.addOracle(reserveTransmitters[i]);
        }
        console.log("Reserve Oracle:", address(reserveOracle));

        // Step 3: Deploy Mint Controller
        console.log("\n3. Deploying Mint Controller...");
        mintController = new MintController(
            admin,
            address(complianceGuard),
            address(reserveOracle)
        );
        console.log("Mint Controller:", address(mintController));

        // Step 4: Deploy Burn Controller (constructor: admin only)
        console.log("\n4. Deploying Burn Controller...");
        burnController = new BurnController(admin);
        console.log("Burn Controller:", address(burnController));

        // Step 5: Deploy Token Registry
        console.log("\n5. Deploying Token Registry...");
        tokenRegistry = new TokenRegistry(admin);
        console.log("Token Registry:", address(tokenRegistry));

        // Step 6: Deploy Token Factory (7 args: admin, implementation, registry, complianceGuard, reserveOracle, mintController, burnController)
        console.log("\n6. Deploying Token Factory...");
        ISO4217WToken tokenImplementation = new ISO4217WToken();
        tokenFactory = new TokenFactory(
            admin,
            address(tokenImplementation),
            address(tokenRegistry),
            address(complianceGuard),
            address(reserveOracle),
            address(mintController),
            address(burnController)
        );
        console.log("Token Factory:", address(tokenFactory));

        // Grant factory role to register tokens
        tokenRegistry.grantRole(keccak256("REGISTRAR_ROLE"), address(tokenFactory));

        // Step 7: Deploy W Tokens
        console.log("\n7. Deploying W Tokens...");

        // Deploy USDW
        usdw = _deployWToken(
            "USDW Token",
            "USDW",
            "USD",
            2, // 2 decimals for USD
            custodian
        );
        console.log("USDW Token:", address(usdw));

        // Deploy EURW
        eurw = _deployWToken(
            "EURW Token",
            "EURW",
            "EUR",
            2, // 2 decimals for EUR
            custodian
        );
        console.log("EURW Token:", address(eurw));

        // Deploy GBPW
        gbpw = _deployWToken(
            "GBPW Token",
            "GBPW",
            "GBP",
            2, // 2 decimals for GBP
            custodian
        );
        console.log("GBPW Token:", address(gbpw));

        audw = _deployWToken("AUDW Token", "AUDW", "AUD", 2, custodian);
        console.log("AUDW Token:", address(audw));
        jpyw = _deployWToken("JPYW Token", "JPYW", "JPY", 2, custodian);
        console.log("JPYW Token:", address(jpyw));
        chfw = _deployWToken("CHFW Token", "CHFW", "CHF", 2, custodian);
        console.log("CHFW Token:", address(chfw));
        cadw = _deployWToken("CADW Token", "CADW", "CAD", 2, custodian);
        console.log("CADW Token:", address(cadw));

        // Step 8: Submit initial reserve reports (admin has ORACLE_ROLE)
        console.log("\n8. Submitting initial reserve reports...");
        reserveOracle.submitReserveReport("USD", 1000000e2, bytes32(0));
        reserveOracle.submitReserveReport("EUR", 500000e2, bytes32(0));
        reserveOracle.submitReserveReport("GBP", 500000e2, bytes32(0));
        reserveOracle.submitReserveReport("AUD", 500000e2, bytes32(0));
        reserveOracle.submitReserveReport("JPY", 50000000e2, bytes32(0));
        reserveOracle.submitReserveReport("CHF", 500000e2, bytes32(0));
        reserveOracle.submitReserveReport("CAD", 500000e2, bytes32(0));

        vm.stopBroadcast();

        console.log("\n=== ISO-4217W Token System Deployment Complete ===");
        console.log("Summary:");
        console.log("  Compliance Guard:", address(complianceGuard));
        console.log("  Reserve Oracle:", address(reserveOracle));
        console.log("  Mint Controller:", address(mintController));
        console.log("  Burn Controller:", address(burnController));
        console.log("  Token Registry:", address(tokenRegistry));
        console.log("  Token Factory:", address(tokenFactory));
        console.log("  USDW Token:", address(usdw));
        console.log("  EURW Token:", address(eurw));
        console.log("  GBPW Token:", address(gbpw));
        console.log("  AUDW Token:", address(audw));
        console.log("  JPYW Token:", address(jpyw));
        console.log("  CHFW Token:", address(chfw));
        console.log("  CADW Token:", address(cadw));
    }

    /**
     * @notice Deploy a W token with proxy pattern
     */
    function _deployWToken(
        string memory name,
        string memory symbol,
        string memory currencyCode,
        uint8 decimals,
        address custodian_
    ) internal returns (ISO4217WToken token) {
        // Deploy implementation
        ISO4217WToken implementation = new ISO4217WToken();

        // Prepare initialization data
        bytes memory initData = abi.encodeWithSelector(
            ISO4217WToken.initialize.selector,
            name,
            symbol,
            currencyCode,
            decimals,
            custodian_,
            address(mintController),
            address(burnController),
            address(complianceGuard),
            admin
        );

        // Deploy proxy
        ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), initData);
        token = ISO4217WToken(address(proxy));

        // Register token in registry (currencyCode, tokenAddress, tokenSymbol, decimals, custodian)
        tokenRegistry.registerToken(
            currencyCode,
            address(token),
            symbol,
            decimals,
            custodian_
        );
    }
}
