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

import "@openzeppelin/contracts/access/Ownable.sol";

/**
 * @title Voting Contract
 * @notice On-chain voting mechanism for governance proposals
 * @dev Simple voting implementation with yes/no votes
 */
contract Voting is Ownable {
    struct Proposal {
        string description;
        uint256 yesVotes;
        uint256 noVotes;
        uint256 startTime;
        uint256 endTime;
        bool executed;
        mapping(address => bool) hasVoted;
    }
    
    Proposal[] public proposals;
    mapping(address => bool) public voters;
    uint256 public votingPeriod = 7 days;
    uint256 public quorum = 50; // 50% of voters
    
    event ProposalCreated(uint256 indexed proposalId, string description);
    event VoteCast(uint256 indexed proposalId, address indexed voter, bool support);
    event ProposalExecuted(uint256 indexed proposalId);
    
    modifier onlyVoter() {
        require(voters[msg.sender], "Voting: not a voter");
        _;
    }
    
    constructor() Ownable(msg.sender) {}
    
    /**
     * @notice Add a voter
     */
    function addVoter(address voter) external onlyOwner {
        voters[voter] = true;
    }
    
    /**
     * @notice Remove a voter
     */
    function removeVoter(address voter) external onlyOwner {
        voters[voter] = false;
    }
    
    /**
     * @notice Create a new proposal
     */
    function createProposal(string memory description) external onlyVoter returns (uint256) {
        uint256 proposalId = proposals.length;
        
        Proposal storage proposal = proposals.push();
        proposal.description = description;
        proposal.startTime = block.timestamp;
        proposal.endTime = block.timestamp + votingPeriod;
        
        emit ProposalCreated(proposalId, description);
        return proposalId;
    }
    
    /**
     * @notice Vote on a proposal
     */
    function vote(uint256 proposalId, bool support) external onlyVoter {
        Proposal storage proposal = proposals[proposalId];
        require(block.timestamp >= proposal.startTime, "Voting: not started");
        require(block.timestamp <= proposal.endTime, "Voting: ended");
        require(!proposal.hasVoted[msg.sender], "Voting: already voted");
        
        proposal.hasVoted[msg.sender] = true;
        
        if (support) {
            proposal.yesVotes++;
        } else {
            proposal.noVotes++;
        }
        
        emit VoteCast(proposalId, msg.sender, support);
    }
    
    /**
     * @notice Execute a proposal if it passes
     */
    function executeProposal(uint256 proposalId) external {
        Proposal storage proposal = proposals[proposalId];
        require(block.timestamp > proposal.endTime, "Voting: not ended");
        require(!proposal.executed, "Voting: already executed");
        
        uint256 totalVotes = proposal.yesVotes + proposal.noVotes;
        require(totalVotes > 0, "Voting: no votes");
        
        // Check quorum
        uint256 voterCount = _getVoterCount();
        require((totalVotes * 100) / voterCount >= quorum, "Voting: quorum not met");
        
        // Check if proposal passed
        require(proposal.yesVotes > proposal.noVotes, "Voting: proposal failed");
        
        proposal.executed = true;
        emit ProposalExecuted(proposalId);
    }
    
    /**
     * @notice Get proposal details
     */
    function getProposal(uint256 proposalId) external view returns (
        string memory description,
        uint256 yesVotes,
        uint256 noVotes,
        uint256 startTime,
        uint256 endTime,
        bool executed
    ) {
        Proposal storage proposal = proposals[proposalId];
        return (
            proposal.description,
            proposal.yesVotes,
            proposal.noVotes,
            proposal.startTime,
            proposal.endTime,
            proposal.executed
        );
    }
    
    /**
     * @notice Get voter count
     */
    function _getVoterCount() internal view returns (uint256) {
        // Simplified - in production, maintain a count
        return 10; // Placeholder
    }
    
    /**
     * @notice Update voting period
     */
    function setVotingPeriod(uint256 newPeriod) external onlyOwner {
        votingPeriod = newPeriod;
    }
    
    /**
     * @notice Update quorum
     */
    function setQuorum(uint256 newQuorum) external onlyOwner {
        require(newQuorum <= 100, "Voting: invalid quorum");
        quorum = newQuorum;
    }
}

