contract UqbarDistribution is ERC721, Ownable {
    uint256 public allocatedSupply = 0;
    uint256 public totalSupply;
    uint256 public burnedSupply;

    uint256 public nextId = 0;

    struct Detail {
        uint256 allocation;
        uint256 atBlock;
        bool burned;
    }

    mapping(uint256 => Detail) public tokenDetails;

    enum Vote { Absent, Aye, Nay }

    struct InflationProposal {
        address proposer;
        uint256 atBlock;
        uint256 newTotalSupply;
        uint256 ayes;
        uint256 nays;
        bool complete;
    }

    InflationProposal[] public proposals;
    mapping(uint256 => mapping(uint256 => Vote)) public votes;

    uint256 public quorumPercent = 15000000000;
    uint256 public quorumDenominator = 100000000000;
    uint256 public votingPeriod = 43200; // 7 days in blocks

    event Proposal(uint256 proposalId, uint256 newSupply, address proposer);
    event Voter(uint256 tokenId, uint256 proposalId, Vote vote);
    event Inflation(uint256 proposalId, uint256 newSupply);

    constructor(string memory _name, string memory _symbol, uint256 _cap)
    ERC721(_name, _symbol) 
    Ownable() {
        totalSupply = _cap;
    }

    // Disable transfers

    function _transfer(address _from, address _to, uint256 _tokenId) internal override {
        revert("Nontransferable");
    }

    // Owner functions

    function mint(address _to, uint256 _amount) external onlyOwner returns (uint256 id) {
        require(_to != address(0) && _to != address(this) && _to != owner(), "Invalid address");
        require(_amount > 0, "No zero amount");
        require(allocatedSupply + _amount <= totalSupply, "Exceeds total supply");

        id = nextId;
        tokenDetails[nextId] = Detail(_amount, block.number, false);
        allocatedSupply += _amount;
        _safeMint(_to, id);
        
        nextId += 1;
    }

    function burn(uint256 _id) external onlyOwner {
        Detail storage tokenDetail_ = tokenDetails[_id];
        require(!tokenDetail_.burned, "Already burned");
        _burn(_id);
        burnedSupply += tokenDetail_.allocation;
        tokenDetail_.burned = true;
    }

    // Inflation-by-vote functions

    function proposeInflation(uint256 _tokenId, uint256 _newTotalSupply) external {
        require(_newTotalSupply > totalSupply, "Proposed supply must exceed current");

        InflationProposal memory proposal;
        proposal.proposer = msg.sender;
        proposal.atBlock = block.number;
        proposal.newTotalSupply = _newTotalSupply;

        if (msg.sender != owner()) {
            require(ownerOf(_tokenId) == msg.sender, "Unauthorized");
            proposal.ayes = tokenDetails[_tokenId].allocation;
            votes[proposals.length][_tokenId] = Vote.Aye;
        }

        proposals.push(proposal);

        emit Proposal(proposals.length - 1, _newTotalSupply, msg.sender);
    }

    function vote(uint256 _tokenId, uint256 _proposalId, Vote _vote) external {
        require(ownerOf(_tokenId) == msg.sender, "Unauthorized");
        
        Vote prev = votes[_proposalId][_tokenId];
        if (prev != _vote) {
            InflationProposal storage proposal_ = proposals[_proposalId];
            require(block.number < proposal_.atBlock + votingPeriod, "Voting period elapsed");

            Detail storage voterDetail_ = tokenDetails[_tokenId];
            require(proposal_.atBlock > voterDetail_.atBlock, "Allocation must predate proposal");

            if (votes[_proposalId][_tokenId] == Vote.Absent) {
                if (_vote == Vote.Aye) { proposal_.ayes += voterDetail_.allocation; }
                else if (_vote == Vote.Nay) { proposal_.nays += voterDetail_.allocation; }
            } else if (prev == Vote.Aye) {
                proposal_.ayes -= voterDetail_.allocation;
                proposal_.nays += voterDetail_.allocation;
            } else {
                proposal_.nays -= voterDetail_.allocation;
                proposal_.ayes += voterDetail_.allocation;
            }
            votes[_proposalId][_tokenId] = _vote;

            emit Voter(_tokenId, _proposalId, _vote);
        }
    }

    function executeProposal(uint256 _pid) external {
        InflationProposal storage proposal_ = proposals[_pid];
        require(block.number > proposal_.atBlock + votingPeriod, "Voting period not elapsed");
        require(!proposal_.complete, "Proposal already executed");
        require(proposal_.newTotalSupply > totalSupply, "Superseded by previous proposal");

        uint256 quorum = allocatedSupply * quorumPercent / quorumDenominator;
        require(proposal_.ayes + proposal_.nays >= quorum, "Does not meet quorum requirement");
        require(proposal_.ayes > proposal_.nays, "Proposal did not pass");

        totalSupply = proposal_.newTotalSupply;
        proposal_.complete = true;

        emit Inflation(totalSupply, _pid);
    }
}
function _transfer(address _from, address _to, uint256 _tokenId) internal override {
    revert("Nontransferable");
}

// Disable transfers