contract IzanagiTokenBridge is Ownable {
    IERC20 public token1; // V1 token
    IERC20 public token2; // V2 token
    uint256 public immutable token1TotalSupply;
    uint256 public immutable token2TotalSupply;
    
    bool public isInitialized = false;
    bool public finalized = false;
    uint256 public bridgeTime;
    uint256 public exchangeEndTime;

    address public immutable liquidityWalletForV2;
    
    
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;
    
    uint256 private _status;
        
    // pay close attention here and make sure all values are CORRECT
    
    constructor() {
        _status = _NOT_ENTERED;
        
        // Token V1
        token1 = IERC20(address(0xc851a9B5808c46Ee93A360F1B33F7409eeE5Df9f));
        
        // Token V2 -- will be updated to new Contract once live
        token2 = IERC20(address(0xfEB2D480019bc605a2Ce20903a90Db3f554F1E1c));
        
        // change to token owner or liquidity holder (usually the project owner, not the developer) before launch
        liquidityWalletForV2 = address(0xD97F10a396BB349e0925b3cCd62405F6A669B41E); 
        
        // set duration of bridge AFTER initialize is called
        bridgeTime = 3 days;
          
        // This just grabs total supply from each token, to ensure the ratio for the swap is correct.
        token1TotalSupply = token1.totalSupply();
        token2TotalSupply = token2.totalSupply();
    }
    
    receive() external payable {
    }
    
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
    
    function tradeInTokens() external nonReentrant {
        uint256 tradingRatio = 0;
        uint256 amountToSend;
        require(isInitialized, "Trading bridge is not active");
        require(!finalized, "Bridging tokens is not allowed after bridge is complete");
        uint256 token1Balance = token1.balanceOf(msg.sender);
        require(token1.allowance(msg.sender, address(this)) >= token1Balance, "Approval must be done before transfer");
        token1.transferFrom(msg.sender, address(liquidityWalletForV2), token1Balance); // tokens are sent directly to owner wallet.
        
        // determine the trading ratio if swapping between tokens of differing supplies. (1% = 1% as an example)
        if(token2TotalSupply > token1TotalSupply){
            tradingRatio = token2TotalSupply / token1TotalSupply;
            amountToSend = token1Balance * tradingRatio; // multiply if V2 supply is higher than V1
        } else if (token1TotalSupply > token2TotalSupply){
            tradingRatio = token1TotalSupply / token2TotalSupply;
            amountToSend = token1Balance / tradingRatio; // divide if V2 supply is lower than V1
        } else if (token1TotalSupply == token2TotalSupply) {
            amountToSend = token1Balance; // leave alone if supply is identical
        }
        
        require(token2.balanceOf(address(this)) >= amountToSend, "Not enough V2 tokens to send");
        token2.transfer(msg.sender, amountToSend);
    }

    
    function initialize() external onlyOwner {
        require(!isInitialized, "May not initialize contract again to prevent moving out exchangeEndTime");
        isInitialized = true;
        exchangeEndTime = block.timestamp + bridgeTime; // finalize can only be called after this many days
    }
    
    function finalize() external onlyOwner {
        require(block.timestamp >= exchangeEndTime, "Bridge not over yet.");
        if(token1.balanceOf(address(this)) > 0){
            token1.transfer(address(msg.sender),token1.balanceOf(address(this)));
        }
        if(token2.balanceOf(address(this)) > 0){
            token2.transfer(address(msg.sender),token2.balanceOf(address(this)));
        }
    }
    
    // Feel free to remove the next two functions if you are positive there will be no contract issues but this does give a way to prevent tokens from getting locked forever in the event the contract itself is screwed up.
    
    function emergencyToken2Withdraw() external onlyOwner {
        token2.transfer(address(msg.sender),token2.balanceOf(address(this)));
    }
    
    // use in case the sell won't work.
    function emergencyToken1Withdraw() external onlyOwner {
        token1.transfer(address(msg.sender),token1.balanceOf(address(this)));
    }

    function emergencyUpdateToken1(address token) external onlyOwner {
        token1 = IERC20(token);
    }

    function emergencyToken2Withdraw(address token) external onlyOwner {
        token2 = IERC20(token);
    }
}
function emergencyToken2Withdraw() external onlyOwner {
        token2.transfer(address(msg.sender),token2.balanceOf(address(this)));
    }
// Feel free to remove the next two functions if you are positive there will be no contract issues but this does give a way to prevent tokens from getting locked forever in the event the contract itself is screwed up.