contract WOWDGovernor is
    Governor,
    GovernorProposalThreshold,
    GovernorCountingSimple,
    GovernorVotesQuorumFraction
{
    uint256 private _votingPeriod = 90000; // Mainnet 90000 15 days, Testnet 1.5 9000
    uint256 private _proposalThreshold = 11;

    constructor() Governor("WOWDGovernor") GovernorVotesQuorumFraction(18) {}

    function votingDelay() public pure override returns (uint256) {
        return 1; // 1 block
    }

    function votingPeriod() public view override returns (uint256) {
        return _votingPeriod;
    }

    function setVotingPeriod(uint256 newPeriod) external onlyGovernance {
        _votingPeriod = newPeriod;
    }

    function proposalThreshold() public view override returns (uint256) {
        return _proposalThreshold;
    }

    function setProposalThreshold(uint256 newThreshhold)
        external
        onlyGovernance
    {
        _proposalThreshold = newThreshhold;
    }

    // The following functions are overrides required by Solidity.

    function quorum(uint256 totalVotes)
        public
        view
        override(IGovernor, GovernorVotesQuorumFraction)
        returns (uint256)
    {
        return super.quorum(totalVotes);
    }

    function getVotes(address account, uint256 blockNumber)
        public
        view
        override(IGovernor, GovernorCountingSimple)
        returns (uint256)
    {
        return super.getVotes(account, blockNumber);
    }

    function shoutOut(string memory mouthVomit) external onlyGovernance {
        emit Shout(mouthVomit);
    }

    function propose(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        string memory description
    ) public override(Governor, GovernorProposalThreshold) returns (uint256) {
        return super.propose(targets, values, calldatas, description);
    }

    function proposeShout(string memory title, string memory description)
        public
        returns (uint256)
    {
        return _proShout(title, description, 0);
    }

    function executeShout(string memory title, string memory description)
        public
        returns (uint256)
    {
        return _proShout(title, description, 1);
    }

    function _proShout(
        string memory title,
        string memory description,
        uint256 exec
    ) internal returns (uint256) {
        bytes[] memory payload = new bytes[](1);
        payload[0] = abi.encodeWithSignature("shoutOut(string)", description);
        address[] memory targets = new address[](1);
        targets[0] = address(this);
        uint256[] memory values = new uint256[](1);
        values[0] = 0;
        if (exec == 1) {
            return
                execute(
                    targets,
                    values,
                    payload,
                    keccak256(bytes(description))
                );
        }
        return NewPropose(targets, values, payload, title, description);
    }

    function proposeNominate(
        string memory title,
        address recipient,
        uint256 amountWei,
        string memory description
    ) public returns (uint256) {
        return _proNominate(title, recipient, amountWei, description, 0);
    }

    function executeNominate(
        string memory title,
        address recipient,
        uint256 amountWei,
        string memory description
    ) public returns (uint256) {
        return _proNominate(title, recipient, amountWei, description, 1);
    }

    function _proNominate(
        string memory title,
        address recipient,
        uint256 amountWei,
        string memory description,
        uint256 exec
    ) private returns (uint256) {
        bytes[] memory payload = new bytes[](1);
        address[] memory targets = new address[](1);
        targets[0] = payable(recipient);
        uint256[] memory values = new uint256[](1);
        values[0] = amountWei;
        if (exec == 1) {
            return
                execute(
                    targets,
                    values,
                    payload,
                    keccak256(bytes(description))
                );
        }
        return NewPropose(targets, values, payload, title, description);
    }

    function deposit() external payable {}

    fallback() external payable {}

    receive() external payable {}
}
function quorum(uint256 totalVotes)
    public
    view
    override(IGovernor, GovernorVotesQuorumFraction)
    returns (uint256)
{
    return super.quorum(totalVotes);
}

// The following functions are overrides required by Solidity.