namespace GeoSus.Server;

using Microsoft.Extensions.Logging;

// Anti-cheat validace pohybu
public class AntiCheat
{
    private readonly ServerConfig _config;
    private readonly ILogger _logger;
    private const int PositionHistorySize = 20;
    
    public AntiCheat(ServerConfig config, ILogger logger)
    {
        _config = config;
        _logger = logger;
    }
    
    // Validuje pohyb hráče a vrací případné cheat violation
    public CheatViolation? ValidateMovement(Player player, Position newPosition)
    {
        var now = DateTime.UtcNow;
        var timeSinceLastUpdate = (now - player.LastPositionUpdate).TotalSeconds;
        
        // Příliš krátký interval ignorujeme
        if (timeSinceLastUpdate < 0.1)
            return null;
            
        var distance = player.Position.DistanceTo(newPosition);
        
        // Teleport detekce
        if (distance > _config.TeleportThresholdMeters)
        {
            var violation = new CheatViolation
            {
                Type = CheatViolationType.Teleport,
                Description = $"Teleport detekován: {distance:F1}m za {timeSinceLastUpdate:F2}s",
                Severity = 10
            };
            
            ApplyViolation(player, violation);
            return violation;
        }
        
        // Speed check
        var speed = distance / timeSinceLastUpdate;
        var maxAllowedSpeed = _config.MaxSpeedMps * 1.5; // 50% tolerance
        
        if (speed > maxAllowedSpeed)
        {
            var violation = new CheatViolation
            {
                Type = CheatViolationType.SpeedHack,
                Description = $"Podezřelá rychlost: {speed:F1}m/s (max {_config.MaxSpeedMps}m/s)",
                Severity = 3
            };
            
            ApplyViolation(player, violation);
            return violation;
        }
        
        // Historie pro detekci pattern
        UpdatePositionHistory(player, newPosition, now);
        
        // Validace historie - průměrná rychlost za delší období
        var historyViolation = ValidatePositionHistory(player);
        if (historyViolation != null)
        {
            ApplyViolation(player, historyViolation);
            return historyViolation;
        }
        
        // Pokud je OK, pomalu snižujeme cheat score
        if (player.CheatScore > 0 && timeSinceLastUpdate > 1)
        {
            player.CheatScore = Math.Max(0, player.CheatScore - 1);
            UpdateCheatStatus(player);
        }
        
        return null;
    }
    
    private void ApplyViolation(Player player, CheatViolation violation)
    {
        player.CheatScore += violation.Severity;
        
        var previousStatus = player.CheatStatus;
        UpdateCheatStatus(player);
        
        if (player.CheatStatus != previousStatus)
        {
            _logger.LogWarning("Cheat status změněn: {Player} -> {Status} (score: {Score})", 
                player.ClientUuid, player.CheatStatus, player.CheatScore);
        }
        
        _logger.LogWarning("Cheat violation: {Player} - {Type}: {Description}", 
            player.ClientUuid, violation.Type, violation.Description);
    }
    
    private void UpdateCheatStatus(Player player)
    {
        player.CheatStatus = player.CheatScore switch
        {
            >= 50 => CheatStatus.Kicked,
            >= 25 => CheatStatus.Restrict,
            >= 10 => CheatStatus.Warn,
            _ => CheatStatus.Ok
        };
    }
    
    private void UpdatePositionHistory(Player player, Position position, DateTime time)
    {
        player.PositionHistory.Enqueue((position, time));
        
        while (player.PositionHistory.Count > PositionHistorySize)
        {
            player.PositionHistory.Dequeue();
        }
    }
    
    private CheatViolation? ValidatePositionHistory(Player player)
    {
        if (player.PositionHistory.Count < 5)
            return null;
            
        var history = player.PositionHistory.ToArray();
        var first = history[0];
        var last = history[^1];
        
        var totalTime = (last.Time - first.Time).TotalSeconds;
        if (totalTime < _config.MovementValidationWindowSec)
            return null;
            
        // Spočítáme celkovou ujetou vzdálenost
        double totalDistance = 0;
        for (int i = 1; i < history.Length; i++)
        {
            totalDistance += history[i - 1].Pos.DistanceTo(history[i].Pos);
        }
        
        var avgSpeed = totalDistance / totalTime;
        
        // Pokud průměrná rychlost za celé období překračuje limit
        if (avgSpeed > _config.MaxSpeedMps * 1.2)
        {
            return new CheatViolation
            {
                Type = CheatViolationType.SustainedSpeedHack,
                Description = $"Dlouhodobě vysoká rychlost: {avgSpeed:F1}m/s za {totalTime:F0}s",
                Severity = 5
            };
        }
        
        return null;
    }
    
    // Validace akce - zda hráč může provést danou akci
    public bool CanPerformAction(Player player, string actionType)
    {
        if (player.CheatStatus == CheatStatus.Kicked)
            return false;
            
        if (player.CheatStatus == CheatStatus.Restrict)
        {
            // Omezené akce pro podezřelé hráče
            var restrictedActions = new[] { "TaskComplete", "Kill", "EmergencyMeeting" };
            if (restrictedActions.Contains(actionType))
            {
                _logger.LogWarning("Akce {Action} blokována pro hráče {Player} (Restrict status)", 
                    actionType, player.ClientUuid);
                return false;
            }
        }
        
        return true;
    }
}

public class CheatViolation
{
    public CheatViolationType Type { get; set; }
    public required string Description { get; set; }
    public int Severity { get; set; }
}

public enum CheatViolationType
{
    SpeedHack,
    Teleport,
    SustainedSpeedHack,
    ActionSpam,
    InvalidAction
}
