// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/interfaces/IERC2981.sol";

/**
 * @title AereNFT
 * @notice Native ERC-721 collection for AERE Network with on-chain royalties (EIP-2981).
 * @dev Permissionless minting: anyone can mint by paying the mint fee in native AERE.
 *      Per-token royalty (creator-set, capped at 10%) flows to the original minter.
 *      Designed to work with AereNFTMarketplace, but conforms to EIP-2981 for any market.
 */
contract AereNFT is ERC721URIStorage, ERC721Enumerable, Ownable, IERC2981 {
    uint96 public constant MAX_ROYALTY_BPS = 1000; // 10%
    uint256 public mintFee = 0.01 ether;           // 0.01 AERE

    address public feeRecipient;
    uint256 private _nextId = 1;

    struct RoyaltyInfo {
        address receiver;
        uint96 royaltyBps;
    }
    mapping(uint256 => RoyaltyInfo) private _royalties;
    mapping(uint256 => address) public minterOf;

    event Minted(uint256 indexed tokenId, address indexed minter, string uri, uint96 royaltyBps);
    event MintFeeUpdated(uint256 newFee);
    event FeeRecipientUpdated(address newRecipient);

    constructor(address _feeRecipient) ERC721("AERE NFT", "AERENFT") {
        feeRecipient = _feeRecipient;
    }

    function mint(string calldata uri, uint96 royaltyBps) external payable returns (uint256) {
        require(msg.value >= mintFee, "fee");
        require(royaltyBps <= MAX_ROYALTY_BPS, "royalty too high");
        uint256 id = _nextId++;
        _safeMint(msg.sender, id);
        _setTokenURI(id, uri);
        _royalties[id] = RoyaltyInfo(msg.sender, royaltyBps);
        minterOf[id] = msg.sender;

        if (msg.value > 0) {
            (bool ok, ) = feeRecipient.call{value: msg.value}("");
            require(ok, "fee transfer");
        }
        emit Minted(id, msg.sender, uri, royaltyBps);
        return id;
    }

    function setMintFee(uint256 newFee) external onlyOwner {
        mintFee = newFee;
        emit MintFeeUpdated(newFee);
    }

    function setFeeRecipient(address newRecipient) external onlyOwner {
        require(newRecipient != address(0), "zero");
        feeRecipient = newRecipient;
        emit FeeRecipientUpdated(newRecipient);
    }

    // EIP-2981
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        external
        view
        override
        returns (address receiver, uint256 royaltyAmount)
    {
        RoyaltyInfo memory r = _royalties[tokenId];
        return (r.receiver, (salePrice * r.royaltyBps) / 10000);
    }

    // Required overrides for ERC721Enumerable + ERC721URIStorage
    function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, firstTokenId, batchSize);
    }

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721Enumerable, ERC721URIStorage, IERC165)
        returns (bool)
    {
        return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
    }
}
