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

import {Script, console} from "forge-std/Script.sol";
import {CompliantUSDTTokenV2} from "../../contracts/tokens/CompliantUSDTTokenV2.sol";
import {CompliantUSDCTokenV2} from "../../contracts/tokens/CompliantUSDCTokenV2.sol";
import {UniversalAssetRegistry} from "../../contracts/registry/UniversalAssetRegistry.sol";

/**
 * @title DeployAndStageCompliantFiatTokensV2ForChain
 * @notice Deploy fresh source-aligned cUSDT V2 / cUSDC V2 contracts, optionally wire governance/disclosure metadata,
 *         and stage them in UniversalAssetRegistry as version-aware GRU assets.
 *
 * Env:
 *   PRIVATE_KEY (required)
 *   INITIAL_OPERATOR (optional; default deployer)
 *   ADMIN (optional; default deployer / OWNER alias)
 *   OWNER (optional alias for ADMIN when ADMIN unset)
 *   INITIAL_SUPPLY (optional; default 0 for safe promotion)
 *   FORWARD_CANONICAL (optional; default true for promotion flow)
 *   GOVERNANCE_CONTROLLER (optional; when set, calls setGovernanceController on fresh deployments)
 *   UNIVERSAL_ASSET_REGISTRY (optional; when set and REGISTER_IN_GRU != 0, registers V2 assets)
 *   REGISTER_IN_GRU (optional; default 1)
 *   TOKEN_URI (optional generic fallback)
 *   REGULATORY_DISCLOSURE_URI (optional)
 *   REPORTING_URI (optional)
 *   CUSDT_V2_TOKEN_URI / CUSDC_V2_TOKEN_URI (optional; per-token overrides)
 *   CUSDT_V2_REGULATORY_DISCLOSURE_URI / CUSDC_V2_REGULATORY_DISCLOSURE_URI (optional; per-token overrides)
 *   CUSDT_V2_REPORTING_URI / CUSDC_V2_REPORTING_URI (optional; per-token overrides)
 *   DEPLOY_CUSDT_V2 / DEPLOY_CUSDC_V2 (optional; default both 1)
 */
contract DeployAndStageCompliantFiatTokensV2ForChain is Script {
    uint256 internal constant DEFAULT_INITIAL_SUPPLY = 0;

    function run() external {
        uint256 pk = vm.envUint("PRIVATE_KEY");
        address deployer = vm.addr(pk);
        address initialOperator = vm.envOr("INITIAL_OPERATOR", deployer);
        address ownerAlias = vm.envOr("OWNER", deployer);
        address admin = vm.envOr("ADMIN", ownerAlias);
        uint256 initialSupply = vm.envOr("INITIAL_SUPPLY", DEFAULT_INITIAL_SUPPLY);
        bool forwardCanonical = vm.envOr("FORWARD_CANONICAL", true);
        address governanceController = vm.envOr("GOVERNANCE_CONTROLLER", address(0));
        address registryAddr = vm.envOr("UNIVERSAL_ASSET_REGISTRY", address(0));
        bool registerInGru = vm.envOr("REGISTER_IN_GRU", uint256(1)) != 0;
        string memory genericTokenURI = vm.envOr("TOKEN_URI", string(""));
        string memory disclosureURI = vm.envOr("REGULATORY_DISCLOSURE_URI", string(""));
        string memory reportingURI = vm.envOr("REPORTING_URI", string(""));

        vm.startBroadcast(pk);

        if (vm.envOr("DEPLOY_CUSDT_V2", uint256(1)) != 0) {
            CompliantUSDTTokenV2 cusdtV2 =
                new CompliantUSDTTokenV2(initialOperator, admin, initialSupply, forwardCanonical);
            _postDeploy(
                address(cusdtV2),
                vm.envOr("CUSDT_V2_TOKEN_URI", genericTokenURI),
                "cUSDT",
                governanceController,
                vm.envOr("CUSDT_V2_REGULATORY_DISCLOSURE_URI", disclosureURI),
                vm.envOr("CUSDT_V2_REPORTING_URI", reportingURI),
                registryAddr,
                registerInGru,
                "Tether USD (Compliant V2)",
                "cUSDT.v2"
            );
            console.log("cUSDT_V2", address(cusdtV2));
        }

        if (vm.envOr("DEPLOY_CUSDC_V2", uint256(1)) != 0) {
            CompliantUSDCTokenV2 cusdcV2 =
                new CompliantUSDCTokenV2(initialOperator, admin, initialSupply, forwardCanonical);
            _postDeploy(
                address(cusdcV2),
                vm.envOr("CUSDC_V2_TOKEN_URI", genericTokenURI),
                "cUSDC",
                governanceController,
                vm.envOr("CUSDC_V2_REGULATORY_DISCLOSURE_URI", disclosureURI),
                vm.envOr("CUSDC_V2_REPORTING_URI", reportingURI),
                registryAddr,
                registerInGru,
                "USD Coin (Compliant V2)",
                "cUSDC.v2"
            );
            console.log("cUSDC_V2", address(cusdcV2));
        }

        vm.stopBroadcast();
    }

    function _postDeploy(
        address token,
        string memory tokenURI,
        string memory symbolDisplay,
        address governanceController,
        string memory disclosureURI,
        string memory reportingURI,
        address registryAddr,
        bool registerInGru,
        string memory name,
        string memory versionedSymbol
    ) internal {
        if (bytes(tokenURI).length > 0 || bytes(symbolDisplay).length > 0) {
            _setPresentationMetadata(token, tokenURI, symbolDisplay);
        }
        if (governanceController != address(0)) {
            _setGovernanceController(token, governanceController);
        }
        if (bytes(disclosureURI).length > 0 || bytes(reportingURI).length > 0) {
            _setDisclosureMetadata(token, disclosureURI, reportingURI);
        }
        if (registerInGru && registryAddr != address(0)) {
            UniversalAssetRegistry(registryAddr).registerGRUCompliantAsset(token, name, versionedSymbol, 6, "International");
        }
    }

    function _setPresentationMetadata(address token, string memory tokenURI, string memory symbolDisplay) internal {
        (bool ok,) = token.call(
            abi.encodeWithSignature(
                "emergencySetPresentationMetadata(bool,string,string)",
                true,
                tokenURI,
                symbolDisplay
            )
        );
        require(ok, "emergencySetPresentationMetadata failed");
    }

    function _setGovernanceController(address token, address governanceController) internal {
        (bool ok,) = token.call(
            abi.encodeWithSignature("setGovernanceController(address)", governanceController)
        );
        require(ok, "setGovernanceController failed");
    }

    function _setDisclosureMetadata(address token, string memory disclosureURI, string memory reportingURI) internal {
        (bool ok,) = token.call(
            abi.encodeWithSignature(
                "emergencySetDisclosureMetadata(string,string)",
                disclosureURI,
                reportingURI
            )
        );
        require(ok, "emergencySetDisclosureMetadata failed");
    }
}
