contract Battle is ERC721Enumerable, ReentrancyGuard, Ownable, Character {
    uint256 public rusNum;
    uint256 public ukrNum;

    uint256 public rusPower;
    uint256 public ukrPower;

    uint256 private tokenCounter;

    address public admin;

    uint256 private constant MAX_SUPPLY = 20000;

    //token id => token power
    mapping(uint256 => uint256) public tokenPower;

    event TokenPowerIncreased(
        uint256 indexed tokenId,
        uint256 indexed addedPower,
        uint256 indexed power
    );

    function mint(uint256 _num, address _to) external onlyAdminOrOwner {
        
        require(_num > 0);
        require(tokenCounter + _num <= MAX_SUPPLY);

        for (uint256 i = 1; i <= _num; i++) 
        {
            _safeMint(_to, tokenCounter + i);
        }
        
        tokenCounter+=_num;
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, tokenId);

        Army _c = _getArmy(tokenId);
        if (from == address(0)) {
            if (_c == Army.Ukrainian) {
                ukrNum++;
            }else
            {
                rusNum++;
            }

            _increaseTokenPower(tokenId, 1);
        }

        if (to == address(0)) {
            if (_c == Army.Ukrainian) {
                ukrNum--;
                ukrPower -= tokenPower[tokenId];
            }else
            {
                rusNum--;
                rusPower -= tokenPower[tokenId];
            }

            delete tokenPower[tokenId];
        }
    }

    function fight(uint256 _tokenId1, uint256 _tokenId2) external nonReentrant {
        require(_isApprovedOrOwner(_msgSender(), _tokenId1), "BTTL: not owner");
        require(_isApprovedOrOwner(_msgSender(), _tokenId2), "BTTL: not owner");
        Army _char1 = _getArmy(_tokenId1);
        Army _char2 = _getArmy(_tokenId2);

        require(_char1 != _char2, "BTTL: Only opposite chars");

        uint256 _char1Power = tokenPower[_tokenId1];
        uint256 _char2Power = tokenPower[_tokenId2];

        

        if (_char1Power == _char2Power) {
            uint256 winner = uint256(
                keccak256(
                    abi.encodePacked(
                        block.timestamp,
                        _msgSender(),
                        rusPower,
                        ukrPower
                    )
                )
            ) % 2;
            if (winner == 0) {
                _burn(_tokenId2);
                _increaseTokenPower(_tokenId1, _char2Power);
            } else {
                _burn(_tokenId1);
                _increaseTokenPower(_tokenId2, _char1Power);
            }
        }else
        {
        
            if (_char1Power > _char2Power) {
                _burn(_tokenId2);
                _increaseTokenPower(_tokenId1, _char2Power);
            }else{
                _burn(_tokenId1);
                _increaseTokenPower(_tokenId2, _char1Power);
                }
        }
    }

    function _increaseTokenPower(uint256 _tokenId, uint256 _increment)
        private
    {
        tokenPower[_tokenId] += _increment;
        Army _t = _getArmy(_tokenId);
        if (_t == Army.Ukrainian) {
            ukrPower += _increment;
        } else {
            rusPower += _increment;
        }
        emit TokenPowerIncreased(_tokenId, _increment, tokenPower[_tokenId]);
    }

    constructor() Ownable() {}

    function svgToImageURI(string memory svg)
        private
        pure
        returns (string memory)
    {
        string memory svgBase64Encoded = Base64.encode(
            bytes(string(abi.encodePacked(svg)))
        );
        return
            string(
                abi.encodePacked("data:image/svg+xml;base64,", svgBase64Encoded)
            );
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override
        returns (string memory)
    {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory _svg;
        string memory _army;
        string memory _forces;
        uint256 maxPower = 0;
        uint256 power = tokenPower[tokenId];
        Army _t = _getArmy(tokenId);
        Forces _f = _getForces(tokenId);

        if (_t == Army.Ukrainian) {
            _army = "UA";
            maxPower = ukrPower;
        } else {
            _army = "RU";
            maxPower = rusPower;
        }

        if (_f == Forces.Aero) {
            _forces = "Aero";
        }

        if (_f == Forces.Tank) {
            _forces = "Tank";
        }

        if (_f == Forces.Motorized) {
            _forces = "Motorized";
        }

        if (_f == Forces.Airborne) {
            _forces = "Airborne";
        }

        _svg = getSvg(power, _f, _t);

        return
            string(
                abi.encodePacked(
                    "data:application/json;base64,",
                    Base64.encode(
                        bytes(
                            string(
                                abi.encodePacked(
                                    '{"name": "',
                                    _army,
                                    " soldier #",
                                    toString(tokenId),
                                    '", "attributes": [ {"trait_type": "Army", "value":"',
                                    _army,
                                    '"}, {"trait_type": "Forces", "value":"',
                                    _forces,
                                    '"}, {"trait_type": "Power", "value":',
                                    toString(power),
                                    ', "max_value":',
                                    toString(maxPower),
                                    '} ], "image":"',
                                    svgToImageURI(_svg),
                                    '"}'
                                )
                            )
                        )
                    )
                )
            );
    }

    function setAdmin(address _admin) external onlyOwner {
        admin = _admin;
    }

    modifier onlyAdminOrOwner() {
        require(
            owner() == msg.sender || admin == msg.sender,
            "Only admin or owner"
        );
        _;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return "Battle";
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return "BTTL";
    }

   
    function totalSupply() public view  returns (uint256) {
        return ukrNum + rusNum;
    }
}
function name() public view virtual override returns (string memory) {
    return "Battle";
}

/**
 * @dev See {IERC721Metadata-name}.
 */