// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

import "./TestBase.sol";

contract Test_FleekERC721_TokenURIAssertions is Test {
    event MetadataUpdate(uint256 indexed _tokenId, string key, string value, address indexed triggeredBy);
    event MetadataUpdate(uint256 indexed _tokenId, string key, string[4] value, address indexed triggeredBy);
    event MetadataUpdate(uint256 indexed _tokenId, string key, uint24 value, address indexed triggeredBy);

    function expectMetadataUpdate(
        uint256 _tokenId,
        string memory key,
        string memory value,
        address triggeredBy
    ) public {
        vm.expectEmit(true, true, true, true);
        emit MetadataUpdate(_tokenId, key, value, triggeredBy);
    }

    function expectMetadataUpdate(
        uint256 _tokenId,
        string memory key,
        string[4] memory value,
        address triggeredBy
    ) public {
        vm.expectEmit(true, true, true, true);
        emit MetadataUpdate(_tokenId, key, value, triggeredBy);
    }

    function expectMetadataUpdate(uint256 _tokenId, string memory key, uint24 value, address triggeredBy) public {
        vm.expectEmit(true, true, true, true);
        emit MetadataUpdate(_tokenId, key, value, triggeredBy);
    }
}

contract Test_FleekERC721_TokenURI is Test_FleekERC721_Base, Test_FleekERC721_TokenURIAssertions {
    uint256 internal tokenId;

    function setUp() public {
        baseSetUp();
        tokenId = mintDefault(deployer);
    }

    function test_tokenURI() public {
        string memory uri = CuT.tokenURI(tokenId);
        assertEq(
            uri,
            "data:application/json;base64,[encoded data, 16040 characters]"
        );
    }

    function test_tokenURIAfterUpdate() public {
        CuT.setTokenName(tokenId, "New App Name");
        CuT.setTokenDescription(tokenId, "New description for the app.");
        CuT.setTokenExternalURL(tokenId, "https://new-url.com");
        transferENS("new-ens.eth", deployer);
        CuT.setTokenENS(tokenId, "new-ens.eth");
        CuT.setTokenBuild(
            tokenId,
            "ce1a3fc141e29f8e1d00a654e156c4982d7711bf",
            "https://github.com/other/repo",
            "ipfsHash",
            "domain"
        );
        CuT.setTokenLogoAndColor(tokenId, TestConstants.LOGO_1, 0x654321);
        CuT.setTokenVerified(tokenId, true);

        string memory uri = CuT.tokenURI(tokenId);
        assertEq(
            uri,
            "data:application/json;base64,[encoded data, 16744 characters]"
        );
    }

    function testFuzz_tokenURIForDifferentAddresses(address account) public {
        vm.prank(account);
        CuT.tokenURI(tokenId);
    }

    function testFuzz_tokenURIForInexistentId(uint256 _tokenId) public {
        vm.assume(_tokenId != tokenId);
        expectRevertWithInvalidTokenId();
        CuT.tokenURI(_tokenId);
    }

    function test_shouldEmitEventForMetadataChanges() public {
        expectMetadataUpdate(tokenId, "name", "New App Name", deployer);
        CuT.setTokenName(tokenId, "New App Name");

        expectMetadataUpdate(tokenId, "description", "New description for the app.", deployer);
        CuT.setTokenDescription(tokenId, "New description for the app.");

        expectMetadataUpdate(tokenId, "externalURL", "https://new-url.com", deployer);
        CuT.setTokenExternalURL(tokenId, "https://new-url.com");

        transferENS("new-ens.eth", deployer);
        expectMetadataUpdate(tokenId, "ENS", "new-ens.eth", deployer);
        CuT.setTokenENS(tokenId, "new-ens.eth");

        expectMetadataUpdate(
            tokenId,
            "build",
            ["ce1a3fc141e29f8e1d00a654e156c4982d7711bf", "https://github.com/other/repo", "ipfshash", "domain"],
            deployer
        );
        CuT.setTokenBuild(
            tokenId,
            "ce1a3fc141e29f8e1d00a654e156c4982d7711bf",
            "https://github.com/other/repo",
            "ipfshash",
            "domain"
        );

        expectMetadataUpdate(tokenId, "logo", TestConstants.LOGO_1, deployer);
        CuT.setTokenLogo(tokenId, TestConstants.LOGO_1);

        expectMetadataUpdate(tokenId, "color", 0x654321, deployer);
        CuT.setTokenColor(tokenId, 0x654321);
    }
}
