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

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/security/Pausable.sol";

/**
 * @title AERE Security Contract
 * @dev Manages security monitoring and threat detection with enhanced security
 */
contract AereSecurity is Ownable, ReentrancyGuard, Pausable {
    
    enum ThreatLevel { Low, Medium, High, Critical }
    enum AlertStatus { Active, Resolved, Investigating }
    
    struct SecurityAlert {
        uint256 id;
        string alertType;
        ThreatLevel severity;
        string message;
        address reporter;
        uint256 timestamp;
        AlertStatus status;
        string resolution;
    }
    
    struct SecurityMetrics {
        uint256 totalAlerts;
        uint256 resolvedAlerts;
        uint256 criticalAlerts;
        uint256 lastScanTime;
        bool systemHealthy;
    }
    
    // State variables
    mapping(uint256 => SecurityAlert) public alerts;
    mapping(address => bool) public authorizedReporters;
    mapping(address => uint256) public reputationScores;
    mapping(address => uint256) public reportCounts;
    mapping(address => uint256) public lastReportTime;
    
    uint256 public alertCount = 0;
    SecurityMetrics public securityMetrics;
    
    // Security parameters
    uint256 public constant RATE_LIMIT_WINDOW = 1 hours;
    uint256 public constant MAX_REPORTS_PER_WINDOW = 10;
    uint256 public constant MIN_REPUTATION_TO_REPORT = 50;
    
    // Events
    event SecurityAlertCreated(uint256 indexed alertId, ThreatLevel severity, string alertType, address indexed reporter);
    event AlertResolved(uint256 indexed alertId, string resolution, address indexed resolver);
    event ThreatDetected(address indexed source, string threatType, ThreatLevel severity, address indexed detector);
    event ReputationUpdated(address indexed entity, uint256 oldScore, uint256 newScore);
    event ReporterAuthorized(address indexed reporter, address indexed authorizer);
    event ReporterRevoked(address indexed reporter, address indexed revoker);
    
    modifier onlyAuthorizedReporter() {
        require(authorizedReporters[msg.sender], "AereSecurity: Not authorized to report");
        require(reputationScores[msg.sender] >= MIN_REPUTATION_TO_REPORT, "AereSecurity: Insufficient reputation");
        _;
    }
    
    modifier rateLimited() {
        require(
            reportCounts[msg.sender] < MAX_REPORTS_PER_WINDOW || 
            block.timestamp > lastReportTime[msg.sender] + RATE_LIMIT_WINDOW,
            "AereSecurity: Rate limit exceeded"
        );
        
        if (block.timestamp > lastReportTime[msg.sender] + RATE_LIMIT_WINDOW) {
            reportCounts[msg.sender] = 0;
        }
        
        reportCounts[msg.sender]++;
        lastReportTime[msg.sender] = block.timestamp;
        _;
    }
    
    constructor() {
        securityMetrics = SecurityMetrics({
            totalAlerts: 0,
            resolvedAlerts: 0,
            criticalAlerts: 0,
            lastScanTime: block.timestamp,
            systemHealthy: true
        });
        
        // Owner is authorized reporter by default with high reputation
        authorizedReporters[msg.sender] = true;
        reputationScores[msg.sender] = 100;
        
        emit ReporterAuthorized(msg.sender, msg.sender);
        emit ReputationUpdated(msg.sender, 0, 100);
    }
    
    /**
     * @dev Add authorized security reporter with reputation check
     */
    function addAuthorizedReporter(address reporter) external onlyOwner {
        require(reporter != address(0), "AereSecurity: Invalid reporter address");
        require(!authorizedReporters[reporter], "AereSecurity: Reporter already authorized");
        
        authorizedReporters[reporter] = true;
        if (reputationScores[reporter] == 0) {
            reputationScores[reporter] = MIN_REPUTATION_TO_REPORT;
        }
        
        emit ReporterAuthorized(reporter, msg.sender);
    }
    
    /**
     * @dev Remove authorized security reporter
     */
    function removeAuthorizedReporter(address reporter) external onlyOwner {
        require(reporter != msg.sender, "AereSecurity: Cannot remove self");
        authorizedReporters[reporter] = false;
        
        emit ReporterRevoked(reporter, msg.sender);
    }
    
    /**
     * @dev Report security alert with enhanced validation
     */
    function reportSecurityAlert(
        string memory alertType,
        ThreatLevel severity,
        string memory message
    ) external onlyAuthorizedReporter rateLimited whenNotPaused nonReentrant returns (uint256) {
        require(bytes(alertType).length > 0 && bytes(alertType).length <= 100, "AereSecurity: Invalid alert type");
        require(bytes(message).length > 0 && bytes(message).length <= 1000, "AereSecurity: Invalid message");
        
        alertCount++;
        uint256 alertId = alertCount;
        
        alerts[alertId] = SecurityAlert({
            id: alertId,
            alertType: alertType,
            severity: severity,
            message: message,
            reporter: msg.sender,
            timestamp: block.timestamp,
            status: AlertStatus.Active,
            resolution: ""
        });
        
        securityMetrics.totalAlerts++;
        if (severity == ThreatLevel.Critical) {
            securityMetrics.criticalAlerts++;
            securityMetrics.systemHealthy = false;
        }
        
        // Update reporter reputation (positive for reporting)
        _updateReputationSafe(msg.sender, reputationScores[msg.sender] + 1);
        
        emit SecurityAlertCreated(alertId, severity, alertType, msg.sender);
        return alertId;
    }
    
    /**
     * @dev Resolve security alert with enhanced validation
     */
    function resolveAlert(uint256 alertId, string memory resolution) external onlyOwner nonReentrant {
        require(alertId > 0 && alertId <= alertCount, "AereSecurity: Alert does not exist");
        require(alerts[alertId].status != AlertStatus.Resolved, "AereSecurity: Alert already resolved");
        require(bytes(resolution).length > 0 && bytes(resolution).length <= 1000, "AereSecurity: Invalid resolution");
        
        alerts[alertId].status = AlertStatus.Resolved;
        alerts[alertId].resolution = resolution;
        
        securityMetrics.resolvedAlerts++;
        
        // Update system health if all critical alerts resolved
        if (alerts[alertId].severity == ThreatLevel.Critical) {
            securityMetrics.criticalAlerts = securityMetrics.criticalAlerts > 0 ? securityMetrics.criticalAlerts - 1 : 0;
            if (securityMetrics.criticalAlerts == 0) {
                securityMetrics.systemHealthy = true;
            }
        }
        
        emit AlertResolved(alertId, resolution, msg.sender);
    }
    
    /**
     * @dev Detect and report threat with enhanced validation
     */
    function detectThreat(
        address source,
        string memory threatType,
        ThreatLevel severity
    ) external onlyAuthorizedReporter rateLimited whenNotPaused nonReentrant {
        require(source != address(0), "AereSecurity: Invalid source address");
        require(bytes(threatType).length > 0 && bytes(threatType).length <= 100, "AereSecurity: Invalid threat type");
        
        // Update reputation score for the source (negative impact)
        if (reputationScores[source] > uint256(severity) + 1) {
            _updateReputationSafe(source, reputationScores[source] - (uint256(severity) + 1));
        } else {
            _updateReputationSafe(source, 0);
        }
        
        // Create alert
        string memory message = string(abi.encodePacked("Threat detected from ", _addressToString(source)));
        this.reportSecurityAlert(threatType, severity, message);
        
        emit ThreatDetected(source, threatType, severity, msg.sender);
    }
    
    /**
     * @dev Update reputation score with bounds checking
     */
    function updateReputation(address entity, uint256 score) external onlyOwner {
        require(entity != address(0), "AereSecurity: Invalid entity address");
        require(score <= 100, "AereSecurity: Score too high");
        
        uint256 oldScore = reputationScores[entity];
        _updateReputationSafe(entity, score);
        
        emit ReputationUpdated(entity, oldScore, score);
    }
    
    /**
     * @dev Internal safe reputation update
     */
    function _updateReputationSafe(address entity, uint256 score) internal {
        uint256 oldScore = reputationScores[entity];
        reputationScores[entity] = score > 100 ? 100 : score;
        
        if (oldScore != reputationScores[entity]) {
            emit ReputationUpdated(entity, oldScore, reputationScores[entity]);
        }
    }
    
    /**
     * @dev Perform security scan (only owner, rate limited)
     */
    function performSecurityScan() external onlyOwner {
        require(block.timestamp >= securityMetrics.lastScanTime + 1 hours, "AereSecurity: Scan rate limited");
        
        securityMetrics.lastScanTime = block.timestamp;
        securityMetrics.systemHealthy = (securityMetrics.criticalAlerts == 0);
    }
    
    /**
     * @dev Emergency pause function
     */
    function emergencyPause() external onlyOwner {
        _pause();
    }
    
    /**
     * @dev Unpause function
     */
    function unpause() external onlyOwner {
        _unpause();
    }
    
    /**
     * @dev Get alert details with existence check
     */
    function getAlert(uint256 alertId) external view returns (SecurityAlert memory) {
        require(alertId > 0 && alertId <= alertCount, "AereSecurity: Alert does not exist");
        return alerts[alertId];
    }
    
    /**
     * @dev Get security metrics
     */
    function getSecurityMetrics() external view returns (SecurityMetrics memory) {
        return securityMetrics;
    }
    
    /**
     * @dev Get reputation score
     */
    function getReputationScore(address entity) external view returns (uint256) {
        return reputationScores[entity];
    }
    
    /**
     * @dev Check if system is healthy
     */
    function isSystemHealthy() external view returns (bool) {
        return securityMetrics.systemHealthy && securityMetrics.criticalAlerts == 0 && !paused();
    }
    
    /**
     * @dev Get active alerts count by severity
     */
    function getActiveAlertsBySeverity(ThreatLevel severity) external view returns (uint256) {
        uint256 count = 0;
        for (uint256 i = 1; i <= alertCount; i++) {
            if (alerts[i].severity == severity && alerts[i].status == AlertStatus.Active) {
                count++;
            }
        }
        return count;
    }
    
    /**
     * @dev Check if address is authorized reporter
     */
    function isAuthorizedReporter(address reporter) external view returns (bool) {
        return authorizedReporters[reporter] && reputationScores[reporter] >= MIN_REPUTATION_TO_REPORT;
    }
    
    /**
     * @dev Get reporter statistics
     */
    function getReporterStats(address reporter) external view returns (
        bool authorized,
        uint256 reputation,
        uint256 reportsInWindow,
        uint256 lastReport
    ) {
        return (
            authorizedReporters[reporter],
            reputationScores[reporter],
            reportCounts[reporter],
            lastReportTime[reporter]
        );
    }
    
    /**
     * @dev Convert address to string
     */
    function _addressToString(address account) internal pure returns (string memory) {
        bytes32 value = bytes32(uint256(uint160(account)));
        bytes memory alphabet = "0123456789abcdef";
        bytes memory str = new bytes(42);
        str[0] = '0';
        str[1] = 'x';
        for (uint256 i = 0; i < 20; i++) {
            str[2+i*2] = alphabet[uint8(value[i + 12] >> 4)];
            str[3+i*2] = alphabet[uint8(value[i + 12] & 0x0f)];
        }
        return string(str);
    }
}
