namespace GeoSus.Server;

using System.Text.Json;
using System.Text.Json.Serialization;

// Konfigurace serveru - všechny herní konstanty
public class ServerConfig
{
    // Síťové
    public int TcpPort { get; set; } = 7777;
    public int HttpPort { get; set; } = 8088;
    public int MaxPacketSizeBytes { get; set; } = 1048576; // 1MB
    
    // Timing
    public int TickMs { get; set; } = 200;
    public int PositionBroadcastRateMs { get; set; } = 1000;
    
    // Pohyb & Anti-Cheat
    public double MaxSpeedMps { get; set; } = 12.0;
    public double MovementValidationWindowSec { get; set; } = 5.0;
    public double TeleportThresholdMeters { get; set; } = 50.0;
    public int CheatScoreWarnThreshold { get; set; } = 10;
    public int CheatScoreRestrictThreshold { get; set; } = 25;
    public int CheatScoreKickThreshold { get; set; } = 50;
    
    // Zabíjení
    public double KillDistanceM { get; set; } = 10.0;
    public int KillCooldownMs { get; set; } = 30000;
    
    // Meetingy
    public double MeetingArrivalRadiusM { get; set; } = 15.0;
    public int ArrivalBaseMs { get; set; } = 30000;
    public int ArrivalSafetyMarginMs { get; set; } = 500;
    public int AllowedLateMs { get; set; } = 2000;
    public int DiscussionPhaseMs { get; set; } = 30000;
    public int VotingPhaseMs { get; set; } = 45000;
    
    // Emergency meeting
    public int EmergencyMeetingCooldownMs { get; set; } = 60000;
    public int MaxEmergencyMeetingsPerPlayer { get; set; } = 1;
    public double EmergencyMeetingCallRadiusM { get; set; } = 15.0; // Vzdálenost od středu mapy pro svolání emergency meeting
    public double ReportDistanceM { get; set; } = 5.0;
    
    // Tasky
    public double TaskStartDistanceM { get; set; } = 3.0;
    public int TaskLeaveDebounceMs { get; set; } = 2000;
    public int TaskProgressKeepaliveMs { get; set; } = 5000;
    
    // Persistence
    public int SnapshotEvents { get; set; } = 200;
    public int SnapshotIntervalMs { get; set; } = 300000;
    public int WalMaxSizeMb { get; set; } = 10;
    public string DataPath { get; set; } = "data";
    
    // Host Migration
    public int HostTimeoutMs { get; set; } = 15000;
    public int ReconnectWindowMs { get; set; } = 60000;
    
    // Lobby
    public int IdleLobbyTtlMs { get; set; } = 3600000;
    public int JoinCodeTtlMs { get; set; } = 86400000; // 24h
    public int MaxPlayersPerLobby { get; set; } = 15;
    public int JoinRateLimitPerMinute { get; set; } = 10;
    
    // Security
    public int SessionKeySizeBytes { get; set; } = 32; // AES-256
    public int RsaKeySizeBits { get; set; } = 2048;
    
    // Stats API
    public int StatsApiRateLimit { get; set; } = 100; // per minute per IP
    public string? StatsApiKey { get; set; } = null;
    
    // Hra - výchozí hodnoty pro nové lobby
    public int DefaultImpostorCount { get; set; } = 1;
    public int DefaultTaskCount { get; set; } = 5;
    public TiePolicy DefaultTiePolicy { get; set; } = TiePolicy.NoEject;
    
    // Sabotage system
    public int SabotageCooldownMs { get; set; } = 30000; // 30s between sabotages
    public int CommsBlackoutDurationMs { get; set; } = 30000; // 30s max duration (or until repaired)
    public int CriticalMeltdownDeadlineMs { get; set; } = 45000; // 45s to fix or impostor wins
    public double RepairStationDistanceM { get; set; } = 5.0; // Must be within 5m to repair
    public int RepairStationHoldMs { get; set; } = 3000; // Must hold for 3s to complete repair
    public int SimultaneousRepairWindowMs { get; set; } = 5000; // 5s window for both stations to be repaired
    
    // Overpass API (Map Data)
    public string OverpassApiUrl { get; set; } = "https://overpass-api.de/api/interpreter";
    public int OverpassTimeoutSec { get; set; } = 30;
    public int OverpassCacheMaxEntries { get; set; } = 100;
    public bool OverpassEnabled { get; set; } = true;
    public double MinTaskSpacingMeters { get; set; } = 20.0; // Minimum spacing between tasks
    
    public static ServerConfig Load(string path)
    {
        ServerConfig config;
        
        if (File.Exists(path))
        {
            var json = File.ReadAllText(path);
            config = JsonSerializer.Deserialize<ServerConfig>(json, JsonOptions.Default) ?? new ServerConfig();
        }
        else
        {
            config = new ServerConfig();
        }
        
        // Override z environment variables (pro Docker)
        config.ApplyEnvironmentOverrides();
        
        return config;
    }
    
    /// <summary>
    /// Aplikuje override hodnot z environment variables.
    /// Prefix: GEOSUS_
    /// Příklady: GEOSUS_TCP_PORT=7777, GEOSUS_HTTP_PORT=8088
    /// </summary>
    private void ApplyEnvironmentOverrides()
    {
        // Síťové
        if (int.TryParse(Environment.GetEnvironmentVariable("GEOSUS_TCP_PORT"), out var tcpPort))
            TcpPort = tcpPort;
        if (int.TryParse(Environment.GetEnvironmentVariable("GEOSUS_HTTP_PORT"), out var httpPort))
            HttpPort = httpPort;
            
        // Data path
        var dataPath = Environment.GetEnvironmentVariable("GEOSUS_DATA_PATH");
        if (!string.IsNullOrEmpty(dataPath))
            DataPath = dataPath;
            
        // Overpass API
        var overpassUrl = Environment.GetEnvironmentVariable("GEOSUS_OVERPASS_URL");
        if (!string.IsNullOrEmpty(overpassUrl))
            OverpassApiUrl = overpassUrl;
            
        // Stats API key
        var apiKey = Environment.GetEnvironmentVariable("GEOSUS_API_KEY");
        if (!string.IsNullOrEmpty(apiKey))
            StatsApiKey = apiKey;
    }
    
    public void Save(string path)
    {
        var json = JsonSerializer.Serialize(this, JsonOptions.Indented);
        File.WriteAllText(path, json);
    }
}

public enum TiePolicy
{
    NoEject,
    Random,
    EjectLowestId
}

public static class JsonOptions
{
    public static readonly JsonSerializerOptions Default = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        Converters = { new JsonStringEnumConverter() },
        WriteIndented = false
    };
    
    public static readonly JsonSerializerOptions Indented = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        Converters = { new JsonStringEnumConverter() },
        WriteIndented = true
    };
}
