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

import {ForkManagement} from 'script/helpers/ForkManagement.sol';
import 'forge-std/Script.sol';
import {ProtocolSharedRevenueDistribution, ProtocolSharedRevenueMinFeeMintModule} from 'contracts/modules/act/collect/ProtocolSharedRevenueMinFeeMintModule.sol';
import {TransparentUpgradeableProxy} from '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol';
import {CollectPublicationAction} from 'contracts/modules/act/collect/CollectPublicationAction.sol';
import {IModuleRegistry} from 'contracts/interfaces/IModuleRegistry.sol';
import {LibString} from 'solady/utils/LibString.sol';

contract DeployMintFeeModule is Script, ForkManagement {
    using stdJson for string;

    struct LensAccount {
        uint256 ownerPk;
        address owner;
        uint256 profileId;
    }

    LensAccount _deployer;
    LensAccount governance;

    string mnemonic;

    address lensHub;
    address collectPublicationAction;
    address moduleRegistry;
    address governanceOwner;
    address proxyAdminContractAdmin;
    address bonsai;

    ProtocolSharedRevenueMinFeeMintModule mintFeeModule;

    function loadPrivateKeys() internal {
        if (isEnvSet('MNEMONIC')) {
            mnemonic = vm.envString('MNEMONIC');
        }

        if (bytes(mnemonic).length == 0) {
            revert('Missing mnemonic');
        }

        console.log('\n');

        (_deployer.owner, _deployer.ownerPk) = deriveRememberKey(mnemonic, 0);
        console.log('Deployer address: %s', address(_deployer.owner));

        (governance.owner, governance.ownerPk) = deriveRememberKey(mnemonic, 1);
        console.log('\n- - - GOVERNANCE: %s', governance.owner);

        console.log('\n');

        console.log('Current block:', block.number);
    }

    struct Currency {
        address addy;
        string symbol;
    }

    // TODO: Use from test/ContractAddresses
    struct Module {
        address addy;
        string name;
    }

    // TODO: Move this somewhere common (also in UpgradeForkTest)
    function findModuleHelper(
        Module[] memory modules,
        string memory moduleNameToFind
    ) internal pure returns (Module memory) {
        for (uint256 i = 0; i < modules.length; i++) {
            if (LibString.eq(modules[i].name, moduleNameToFind)) {
                return modules[i];
            }
        }
        revert('Module not found');
    }

    function saveModule(
        string memory moduleName,
        address moduleAddress,
        string memory lensVersion,
        string memory moduleType
    ) internal {
        // console.log('Saving %s (%s) into addresses under %s environment', moduleName, moduleAddress, targetEnv);
        string[] memory inputs = new string[](7);
        inputs[0] = 'node';
        inputs[1] = 'script/helpers/saveAddress.js';
        inputs[2] = targetEnv;
        inputs[3] = moduleName;
        inputs[4] = vm.toString(moduleAddress);
        inputs[5] = lensVersion;
        inputs[6] = moduleType;
        // bytes memory res =
        vm.ffi(inputs);
        // string memory output = abi.decode(res, (string));
        // console.log(output);
    }

    function _logDeployedModule(address deployedAddress, string memory moduleName, string memory moduleType) internal {
        string memory lensVersion = 'v2';
        console.log('\n+ + + ', moduleName, ': ', deployedAddress);
        saveModule(moduleName, deployedAddress, lensVersion, moduleType);
    }

    function loadBaseAddresses() internal override {
        lensHub = json.readAddress(string(abi.encodePacked('.', targetEnv, '.LensHub')));
        vm.label(lensHub, 'LensHub');
        console.log('Lens Hub Proxy: %s', lensHub);

        Module[] memory actModules = abi.decode(
            vm.parseJson(json, string(abi.encodePacked('.', targetEnv, '.Modules.v2.act'))),
            (Module[])
        );
        collectPublicationAction = findModuleHelper(actModules, 'CollectPublicationAction').addy;
        vm.label(collectPublicationAction, 'CollectPublicationAction');
        console.log('CollectPublicationAction: %s', collectPublicationAction);

        moduleRegistry = json.readAddress(string(abi.encodePacked('.', targetEnv, '.ModuleRegistry')));
        vm.label(moduleRegistry, 'ModuleRegistry');
        console.log('ModuleRegistry: %s', moduleRegistry);

        governanceOwner = json.readAddress(string(abi.encodePacked('.', targetEnv, '.GovernanceContractAdmin')));
        vm.label(governanceOwner, 'GovernanceOwner');
        console.log('Governance Owner: %s', governanceOwner);

        proxyAdminContractAdmin = json.readAddress(
            string(abi.encodePacked('.', targetEnv, '.ProxyAdminContractAdmin'))
        );
        vm.label(proxyAdminContractAdmin, 'ProxyAdminContractAdmin');
        console.log('Proxy Admin Contract Admin: %s', proxyAdminContractAdmin);

        Currency[] memory currencies = abi.decode(
            vm.parseJson(json, string(abi.encodePacked('.', targetEnv, '.Currencies'))),
            (Currency[])
        );

        for (uint256 i = 0; i < currencies.length; i++) {
            if (LibString.eq(currencies[i].symbol, 'BONSAI')) {
                bonsai = currencies[i].addy;
            }
        }
        vm.label(bonsai, 'BONSAI');
        console.log('BONSAI: %s', bonsai);
    }

    function run(string memory targetEnv_) external {
        targetEnv = targetEnv_;
        loadJson();
        checkNetworkParams();
        loadBaseAddresses();
        loadPrivateKeys();
        deploy();
        moduleRegistryActions();
        governanceActions();
    }

    function deploy() internal {
        vm.startBroadcast(_deployer.ownerPk);
        {
            address mintFeeModuleImpl = address(
                new ProtocolSharedRevenueMinFeeMintModule({
                    hub: lensHub,
                    actionModule: collectPublicationAction,
                    moduleRegistry: moduleRegistry,
                    moduleOwner: governanceOwner
                })
            );
            console.log(
                '\n* * * Deployed ProtocolSharedRevenueMinFeeMintModule implementation at: ',
                mintFeeModuleImpl
            );
            console.log('With parameters:');
            console.log('\tHub: ', lensHub);
            console.log('\tAction Module: ', collectPublicationAction);
            console.log('\tModule Registry: ', moduleRegistry);
            console.log('\tModule Owner: ', governanceOwner);

            mintFeeModule = ProtocolSharedRevenueMinFeeMintModule(
                address(
                    new TransparentUpgradeableProxy(
                        mintFeeModuleImpl,
                        proxyAdminContractAdmin,
                        abi.encodeCall(mintFeeModule.initialize, (governanceOwner))
                    )
                )
            );

            _logDeployedModule(address(mintFeeModule), 'ProtocolSharedRevenueMinFeeMintModule', 'collect');
        }
        vm.stopBroadcast();
    }

    function moduleRegistryActions() internal {
        vm.startBroadcast(_deployer.ownerPk);
        IModuleRegistry(moduleRegistry).registerErc20Currency(bonsai);
        console.log('\n* * * BONSAI registered as currency: ', bonsai);

        CollectPublicationAction(collectPublicationAction).registerCollectModule(address(mintFeeModule));
        console.log('\n* * * MintFeeModule registered as collect module in CollectPublicationAction');
        vm.stopBroadcast();
    }

    function governanceActions() internal {
        console.log('Owner of mintFeeModule:', mintFeeModule.owner());
        vm.startBroadcast(governance.ownerPk);
        {
            mintFeeModule.setMintFeeParams(bonsai, 10 ether);
            console.log('\n* * * MintFeeModule mint fee set to 10 BONSAI');

            mintFeeModule.setProtocolSharedRevenueDistribution(
                ProtocolSharedRevenueDistribution({
                    creatorSplit: 5000,
                    protocolSplit: 2000,
                    creatorClientSplit: 1500,
                    executorClientSplit: 1500
                })
            );
            console.log('\n* * * MintFeeModule revenue distribution set to:');
            console.log('\tCreator: 50%');
            console.log('\tProtocol: 20%');
            console.log('\tCreator Client: 15%');
            console.log('\tExecutor Client: 15%');
        }
        vm.stopBroadcast();
    }
}
