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

import "forge-std/Script.sol";
import {IDiamondCut} from "@gru/interfaces/IDiamondCut.sol";
import {IndexFacet} from "@gru/facets/IndexFacet.sol";
import {MonetaryFacet} from "@gru/facets/MonetaryFacet.sol";
import {GovernanceFacet} from "@gru/facets/GovernanceFacet.sol";
import {AccessFacet} from "@gru/facets/AccessFacet.sol";
import {IAccess} from "@gru/interfaces/IAccess.sol";
import {IGovernance} from "@gru/interfaces/IGovernance.sol";
import {RWAInstrumentFacet} from "../../contracts/rwa/diamond/facets/RWAInstrumentFacet.sol";
import {RWADocumentFacet} from "../../contracts/rwa/diamond/facets/RWADocumentFacet.sol";
import {RWAStandardsRegistryFacet} from "../../contracts/rwa/diamond/facets/RWAStandardsRegistryFacet.sol";

/**
 * @title UpgradeM00DiamondHubComplete138
 * @notice Add GRC Index/Monetary/Governance facets, RWA read selectors, AccessFacet.hasRoles; grant GRC roles.
 */
contract UpgradeM00DiamondHubComplete138 is Script {
    uint256 internal constant ROLE_ALL_GRC = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3);

    function run() external {
        uint256 pk = vm.envUint("PRIVATE_KEY");
        address deployer = vm.addr(pk);
        address diamond = vm.envAddress("M00_DIAMOND_HUB");
        address governance = vm.envOr("GOVERNANCE_CONTROLLER", deployer);
        address accessFacet = vm.envAddress("M00_ACCESS_FACET");
        address rwaInst = vm.envAddress("M00_RWA_INSTRUMENT_FACET");
        address rwaDoc = vm.envAddress("M00_RWA_DOCUMENT_FACET");
        address rwaStd = vm.envAddress("M00_RWA_STANDARDS_FACET");

        vm.startBroadcast(pk);

        IndexFacet index = new IndexFacet();
        MonetaryFacet monetary = new MonetaryFacet();
        GovernanceFacet govFacet = new GovernanceFacet();

        IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](7);
        cut[0] = _add(address(index), _indexSelectors());
        cut[1] = _add(address(monetary), _monetarySelectors());
        cut[2] = _add(address(govFacet), _governanceSelectors());
        cut[3] = _add(accessFacet, _accessExtraSelectors());
        cut[4] = _add(rwaInst, _rwaInstViewSelectors());
        cut[5] = _add(rwaDoc, _rwaDocViewSelectors());
        cut[6] = _add(rwaStd, _rwaStdViewSelectors());

        IDiamondCut(diamond).diamondCut(cut, address(0), "");

        IAccess(diamond).grantRoles(governance, ROLE_ALL_GRC);
        if (governance != deployer) {
            IAccess(diamond).grantRoles(deployer, ROLE_ALL_GRC);
        }

        IGovernance(diamond).setGovernanceParams(86_400, 5_000);

        console.log("M00Diamond", diamond);
        console.log("IndexFacet", address(index));
        console.log("MonetaryFacet", address(monetary));
        console.log("GovernanceFacet", address(govFacet));
        vm.stopBroadcast();
    }

    function _add(address facet, bytes4[] memory sels)
        internal
        pure
        returns (IDiamondCut.FacetCut memory)
    {
        return IDiamondCut.FacetCut({
            facetAddress: facet,
            action: IDiamondCut.FacetCutAction.Add,
            functionSelectors: sels
        });
    }

    function _indexSelectors() internal pure returns (bytes4[] memory s) {
        s = new bytes4[](8);
        s[0] = IndexFacet.setWeights.selector;
        s[1] = IndexFacet.getIndex.selector;
        s[2] = IndexFacet.recalcLiCRI.selector;
        s[3] = IndexFacet.recalcLiCRIWeighted.selector;
        s[4] = IndexFacet.setDashboardComposite.selector;
        s[5] = IndexFacet.getLiCRI.selector;
        s[6] = IndexFacet.setIndexValue.selector;
        s[7] = IndexFacet.getIndexValue.selector;
    }

    function _monetarySelectors() internal pure returns (bytes4[] memory s) {
        s = new bytes4[](6);
        s[0] = MonetaryFacet.mintM1.selector;
        s[1] = MonetaryFacet.burnM1.selector;
        s[2] = MonetaryFacet.issueM0.selector;
        s[3] = MonetaryFacet.redeemM0.selector;
        s[4] = MonetaryFacet.setScalarS.selector;
        s[5] = MonetaryFacet.getLayers.selector;
    }

    function _governanceSelectors() internal pure returns (bytes4[] memory s) {
        s = new bytes4[](9);
        s[0] = GovernanceFacet.proposeCut.selector;
        s[1] = GovernanceFacet.queueCut.selector;
        s[2] = GovernanceFacet.executeCut.selector;
        s[3] = GovernanceFacet.emergencyBrake.selector;
        s[4] = GovernanceFacet.timelock.selector;
        s[5] = GovernanceFacet.quorumBps.selector;
        s[6] = GovernanceFacet.eta.selector;
        s[7] = GovernanceFacet.proposer.selector;
        s[8] = GovernanceFacet.setGovernanceParams.selector;
    }

    function _accessExtraSelectors() internal pure returns (bytes4[] memory s) {
        s = new bytes4[](1);
        s[0] = AccessFacet.hasRoles.selector;
    }

    function _rwaInstViewSelectors() internal pure returns (bytes4[] memory s) {
        s = new bytes4[](2);
        s[0] = RWAInstrumentFacet.getIssuanceMode.selector;
        s[1] = RWAInstrumentFacet.getTokenPointer.selector;
    }

    function _rwaDocViewSelectors() internal pure returns (bytes4[] memory s) {
        s = new bytes4[](2);
        s[0] = RWADocumentFacet.documentCount.selector;
        s[1] = RWADocumentFacet.getDocument.selector;
    }

    function _rwaStdViewSelectors() internal pure returns (bytes4[] memory s) {
        s = new bytes4[](2);
        s[0] = RWAStandardsRegistryFacet.isStandardEnabled.selector;
        s[1] = RWAStandardsRegistryFacet.assetStandardFacet.selector;
    }
}
