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

import "forge-std/Script.sol";
import {CompliantWrappedToken} from "../../contracts/tokens/CompliantWrappedToken.sol";

/**
 * @title DeployCWTokens
 * @notice Deploy all cW* (CompliantWrappedToken) on the current chain; grant MINTER_ROLE and BURNER_ROLE to bridge.
 * @dev Run with --rpc-url <CHAIN_RPC> --chain-id <ID>. Set CW_BRIDGE_ADDRESS (or CCIP receiver) to receive MINTER_ROLE/BURNER_ROLE.
 *
 * Env:
 *   PRIVATE_KEY (required)
 *   CW_BRIDGE_ADDRESS (required) — address that can mint/burn (e.g. CCIP receiver or custom bridge)
 *   CW_STRICT_MODE=1 (optional) — revoke deployer MINTER/BURNER after bridge grant
 *   CW_GOVERNANCE_ADMIN=0x... (optional) — grant DEFAULT_ADMIN_ROLE to governance; if strict, revoke deployer admin when governance is set
 *   CW_FREEZE_OPERATIONAL_ROLES=1 (optional) — freeze future MINTER/BURNER changes after setup
 *   DEPLOY_CWUSDT=1, DEPLOY_CWUSDC=1, DEPLOY_CWUSDW=1, DEPLOY_CWEURC=1, ... (default all 1; set 0 to skip a token)
 */
contract DeployCWTokens is Script {
    uint8 constant DECIMALS = 6;

    function run() external {
        uint256 pk = vm.envUint("PRIVATE_KEY");
        address deployer = vm.addr(pk);
        address bridge = vm.envAddress("CW_BRIDGE_ADDRESS");
        bool strictMode = vm.envOr("CW_STRICT_MODE", uint256(0)) == 1;
        bool freezeOperationalRoles = vm.envOr("CW_FREEZE_OPERATIONAL_ROLES", uint256(0)) == 1;
        address governanceAdmin = vm.envOr("CW_GOVERNANCE_ADMIN", address(0));
        require(bridge != address(0), "CW_BRIDGE_ADDRESS required");

        vm.startBroadcast(pk);

        _deployOne(deployer, "Wrapped cUSDT", "cWUSDT", "DEPLOY_CWUSDT", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cUSDC", "cWUSDC", "DEPLOY_CWUSDC", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cAUSDT", "cWAUSDT", "DEPLOY_CWAUSDT", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cUSDW", "cWUSDW", "DEPLOY_CWUSDW", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cEURC", "cWEURC", "DEPLOY_CWEURC", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cEURT", "cWEURT", "DEPLOY_CWEURT", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cGBPC", "cWGBPC", "DEPLOY_CWGBPC", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cGBPT", "cWGBPT", "DEPLOY_CWGBPT", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cAUDC", "cWAUDC", "DEPLOY_CWAUDC", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cJPYC", "cWJPYC", "DEPLOY_CWJPYC", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cCHFC", "cWCHFC", "DEPLOY_CWCHFC", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cCADC", "cWCADC", "DEPLOY_CWCADC", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cXAUC", "cWXAUC", "DEPLOY_CWXAUC", bridge, strictMode, governanceAdmin, freezeOperationalRoles);
        _deployOne(deployer, "Wrapped cXAUT", "cWXAUT", "DEPLOY_CWXAUT", bridge, strictMode, governanceAdmin, freezeOperationalRoles);

        vm.stopBroadcast();
    }

    function _deployOne(
        address admin,
        string memory name,
        string memory symbol,
        string memory envKey,
        address bridge,
        bool strictMode,
        address governanceAdmin,
        bool freezeOperationalRoles
    ) internal {
        if (vm.envOr(envKey, uint256(1)) == 0) return;
        CompliantWrappedToken t = new CompliantWrappedToken(name, symbol, DECIMALS, admin);
        t.grantRole(t.MINTER_ROLE(), bridge);
        t.grantRole(t.BURNER_ROLE(), bridge);

        if (strictMode) {
            t.revokeRole(t.MINTER_ROLE(), admin);
            t.revokeRole(t.BURNER_ROLE(), admin);
        }

        if (governanceAdmin != address(0) && governanceAdmin != admin) {
            t.grantRole(t.DEFAULT_ADMIN_ROLE(), governanceAdmin);
        }

        if (freezeOperationalRoles) {
            t.freezeOperationalRoles();
        }

        if (strictMode && governanceAdmin != address(0) && governanceAdmin != admin) {
            t.revokeRole(t.DEFAULT_ADMIN_ROLE(), admin);
        }

        console.log(symbol, address(t));
        console.log("  strictMode", strictMode);
        console.log("  governanceAdmin", governanceAdmin);
        console.log("  operationalRolesFrozen", t.operationalRolesFrozen());
        console.log("  deployerHasMinter", t.hasRole(t.MINTER_ROLE(), admin));
        console.log("  deployerHasBurner", t.hasRole(t.BURNER_ROLE(), admin));
        console.log("  bridgeHasMinter", t.hasRole(t.MINTER_ROLE(), bridge));
        console.log("  bridgeHasBurner", t.hasRole(t.BURNER_ROLE(), bridge));
    }
}
