// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import { Script } from "forge-std/Script.sol";
import { MultisigGovernanceV3 } from "../contracts/governance/MultisigGovernanceV3.sol";
import { BasePilotAccessControllerV3 } from "../contracts/pilot/BasePilotAccessControllerV3.sol";
import { AccountabilityBondV3Safe } from "../contracts/bonds/AccountabilityBondV3Safe.sol";
import { SafeBondFactoryV3 } from "../contracts/bonds/SafeBondFactoryV3.sol";
import { PartnershipBondFactoryV3 } from "../contracts/bonds/PartnershipBondFactoryV3.sol";
import { AccountabilityBondFactoryV3 } from "../contracts/bonds/AccountabilityBondFactoryV3.sol";
import { ThresholdConsensusV3 } from "../contracts/consensus/ThresholdConsensusV3.sol";

/// @dev Ordinary bootstrap contract used so the Script contract's ephemeral
/// address is never used in address derivation.
contract BasePilotForkBootstrap {
    address internal constant SIGNER_A = address(0xA11CE);
    address internal constant SIGNER_B = address(0xB0B);
    address internal constant SIGNER_C = address(0xC0C);
    address internal constant SIGNER_D = address(0xD0D);
    address internal constant SIGNER_E = address(0xE0E);
    address internal constant GUARDIAN = address(0x600D);
    uint256 internal constant TIMELOCK = 24 hours;

    struct NativeBondCaps {
        uint256 partnershipParty;
        uint256 partnershipBond;
        uint256 partnershipAggregate;
        uint256 accountabilityBond;
        uint256 accountabilityAggregate;
    }

    function deploy(NativeBondCaps calldata caps)
        external
        returns (
            address governanceAddress,
            address controllerAddress,
            address consensusAddress,
            address partnershipFactoryAddress,
            address accountabilityFactoryAddress,
            address factoryAddress
        )
    {
        address[] memory signers = new address[](5);
        signers[0] = SIGNER_A;
        signers[1] = SIGNER_B;
        signers[2] = SIGNER_C;
        signers[3] = SIGNER_D;
        signers[4] = SIGNER_E;
        address[] memory guardianPauseTargets = new address[](0);
        MultisigGovernanceV3 governance = new MultisigGovernanceV3(
            signers, 3, TIMELOCK, TIMELOCK, GUARDIAN, TIMELOCK, guardianPauseTargets, new address[](0), new bytes32[](0)
        );
        BasePilotAccessControllerV3 controller =
            new BasePilotAccessControllerV3(address(governance), 0.4 ether, 0.2 ether);
        ThresholdConsensusV3 consensus = new ThresholdConsensusV3(address(governance), 3);

        // Nonce six is the canonical SafeBondFactory deployment. Specialized
        // factories are created first but bind only that exact coordinator.
        address predictedFactory =
            address(uint160(uint256(keccak256(abi.encodePacked(hex"d694", address(this), hex"06")))));
        PartnershipBondFactoryV3 partnershipFactory = new PartnershipBondFactoryV3(
            predictedFactory,
            address(governance),
            address(consensus),
            address(0),
            caps.partnershipParty,
            caps.partnershipBond,
            caps.partnershipAggregate,
            address(controller)
        );
        bytes memory accountabilityChildInitCode = abi.encodePacked(
            type(AccountabilityBondV3Safe).creationCode,
            abi.encode(
                address(governance),
                address(consensus),
                address(0),
                caps.accountabilityBond,
                caps.accountabilityAggregate,
                address(controller)
            )
        );
        AccountabilityBondFactoryV3 accountabilityFactory = new AccountabilityBondFactoryV3(
            predictedFactory,
            address(governance),
            address(consensus),
            address(0),
            caps.accountabilityBond,
            caps.accountabilityAggregate,
            address(controller),
            accountabilityChildInitCode,
            bytes32(uint256(1))
        );

        SafeBondFactoryV3 factory = new SafeBondFactoryV3(
            address(governance),
            address(consensus),
            address(0),
            address(controller),
            caps.partnershipParty,
            caps.partnershipBond,
            caps.partnershipAggregate,
            caps.accountabilityBond,
            caps.accountabilityAggregate,
            address(partnershipFactory).codehash,
            address(accountabilityFactory).codehash,
            bytes32(uint256(1)),
            bytes32(uint256(1)),
            keccak256(accountabilityChildInitCode)
        );
        require(address(factory) == predictedFactory, "deployment order changed");
        require(!controller.deployEnabled() && !controller.writeEnabled(), "pilot must start closed");
        require(factory.owner() == address(governance), "factory must bind governance");
        require(factory.consensus() == address(consensus), "factory must bind consensus");
        require(factory.disputeRegistry() == address(0), "retired dispute binding must be zero");

        return (
            address(governance),
            address(controller),
            address(consensus),
            address(partnershipFactory),
            address(accountabilityFactory),
            address(factory)
        );
    }
}

/// @notice Creates the bootstrap portion of the Base V3 pilot on an ephemeral
/// fork only. This script has no broadcast call and never reads a private key.
/// @dev The corresponding fork test executes the governance configuration,
/// rollback, and safe-exit assertions.
contract BasePilotForkSimulation is Script {
    uint256 internal constant BASE_CHAIN_ID = 8453;

    event SimulatedAddress(string label, address value);

    function run() external {
        string memory rpcUrl = vm.envString("BASE_RPC_URL");
        vm.createSelectFork(rpcUrl);
        require(block.chainid == BASE_CHAIN_ID, "BASE_RPC_URL must be a Base endpoint");

        BasePilotForkBootstrap.NativeBondCaps memory caps = BasePilotForkBootstrap.NativeBondCaps({
            partnershipParty: vm.envUint("PARTNERSHIP_PARTY_NATIVE_PRINCIPAL_WEI"),
            partnershipBond: vm.envUint("PARTNERSHIP_BOND_NATIVE_PRINCIPAL_WEI"),
            partnershipAggregate: vm.envUint("PARTNERSHIP_AGGREGATE_NATIVE_LIABILITY_WEI"),
            accountabilityBond: vm.envUint("ACCOUNTABILITY_BOND_NATIVE_PRINCIPAL_WEI"),
            accountabilityAggregate: vm.envUint("ACCOUNTABILITY_AGGREGATE_NATIVE_LIABILITY_WEI")
        });
        BasePilotForkBootstrap bootstrap = new BasePilotForkBootstrap();
        (
            address governance,
            address controller,
            address consensus,
            address partnershipFactory,
            address accountabilityFactory,
            address factory
        ) = bootstrap.deploy(caps);

        emit SimulatedAddress("simulated_governance", governance);
        emit SimulatedAddress("simulated_controller", controller);
        emit SimulatedAddress("simulated_consensus", consensus);
        emit SimulatedAddress("simulated_partnership_factory", partnershipFactory);
        emit SimulatedAddress("simulated_accountability_factory", accountabilityFactory);
        emit SimulatedAddress("simulated_bond_factory", factory);
    }
}
