using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;

namespace Oxide.Plugins
{
    [Info("Corrosion Companion", "Corrosion", "1.0.0")]
    [Description("Connects Rust server to Corrosion admin panel via HTTP API")]
    public class CorrosionCompanion : RustPlugin
    {
        #region Configuration

        private Configuration config;

        public class Configuration
        {
            [JsonProperty("API Base URL")]
            public string ApiBaseUrl { get; set; } = "https://api.corrosion.example.com";

            [JsonProperty("License Key")]
            public string LicenseKey { get; set; } = "YOUR_LICENSE_KEY_HERE";

            [JsonProperty("Heartbeat Interval (seconds)")]
            public int HeartbeatInterval { get; set; } = 60;

            [JsonProperty("Send Player Events")]
            public bool SendPlayerEvents { get; set; } = true;

            [JsonProperty("Send Chat Events")]
            public bool SendChatEvents { get; set; } = false;

            [JsonProperty("Debug Mode")]
            public bool DebugMode { get; set; } = false;
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<Configuration>();
                if (config == null)
                {
                    throw new Exception("Config is null");
                }
            }
            catch
            {
                PrintWarning("Config file corrupt or missing, generating new one");
                LoadDefaultConfig();
            }
        }

        protected override void LoadDefaultConfig()
        {
            config = new Configuration();
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        #endregion

        #region Lifecycle Hooks

        private Timer heartbeatTimer;

        void OnServerInitialized()
        {
            Puts("Corrosion Companion initialized");

            // Validate configuration
            if (string.IsNullOrEmpty(config.LicenseKey) || config.LicenseKey == "YOUR_LICENSE_KEY_HERE")
            {
                PrintError("License key not configured! Edit oxide/config/CorrosionCompanion.json");
                return;
            }

            // Send initial check-in
            CheckIn();

            // Start heartbeat timer
            heartbeatTimer = timer.Every(config.HeartbeatInterval, () =>
            {
                SendHeartbeat();
            });

            Puts($"Heartbeat started (every {config.HeartbeatInterval}s)");
        }

        void Unload()
        {
            heartbeatTimer?.Destroy();
            Puts("Corrosion Companion unloaded");
        }

        #endregion

        #region Player Event Hooks

        void OnPlayerConnected(BasePlayer player)
        {
            if (!config.SendPlayerEvents) return;

            var data = new Dictionary<string, object>
            {
                { "event", "player_connected" },
                { "player_id", player.UserIDString },
                { "player_name", player.displayName },
                { "ip_address", player.net?.connection?.ipaddress ?? "unknown" },
                { "timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
            };

            SendEvent("player_connected", data);

            if (config.DebugMode)
            {
                Puts($"Player connected: {player.displayName} ({player.UserIDString})");
            }
        }

        void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (!config.SendPlayerEvents) return;

            var data = new Dictionary<string, object>
            {
                { "event", "player_disconnected" },
                { "player_id", player.UserIDString },
                { "player_name", player.displayName },
                { "reason", reason ?? "unknown" },
                { "timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
            };

            SendEvent("player_disconnected", data);

            if (config.DebugMode)
            {
                Puts($"Player disconnected: {player.displayName} (Reason: {reason})");
            }
        }

        object OnPlayerChat(BasePlayer player, string message)
        {
            if (!config.SendChatEvents) return null;

            var data = new Dictionary<string, object>
            {
                { "event", "player_chat" },
                { "player_id", player.UserIDString },
                { "player_name", player.displayName },
                { "message", message },
                { "timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
            };

            SendEvent("player_chat", data);

            return null; // Don't block the message
        }

        #endregion

        #region API Communication

        private void CheckIn()
        {
            var data = new Dictionary<string, object>
            {
                { "license_key", config.LicenseKey },
                { "server_name", ConVar.Server.hostname },
                { "server_description", ConVar.Server.description },
                { "server_url", ConVar.Server.url },
                { "max_players", ConVar.Server.maxplayers },
                { "world_size", ConVar.Server.worldsize },
                { "seed", ConVar.Server.seed },
                { "plugin_version", Version.ToString() },
                { "server_version", Rust.Protocol.network.ToString() }
            };

            SendApiRequest("/api/plugin/checkin", data, (code, response) =>
            {
                if (code == 200)
                {
                    Puts("Check-in successful");

                    if (config.DebugMode)
                    {
                        Puts($"Response: {response}");
                    }
                }
                else
                {
                    PrintWarning($"Check-in failed: HTTP {code}");
                }
            });
        }

        private void SendHeartbeat()
        {
            var data = new Dictionary<string, object>
            {
                { "license_key", config.LicenseKey },
                { "player_count", BasePlayer.activePlayerList.Count },
                { "max_players", ConVar.Server.maxplayers },
                { "fps", Performance.current.frameRate },
                { "entity_count", BaseNetworkable.serverEntities.Count },
                { "uptime_seconds", Time.realtimeSinceStartup },
                { "timestamp", DateTimeOffset.UtcNow.ToUnixTimeSeconds() }
            };

            SendApiRequest("/api/plugin/heartbeat", data, (code, response) =>
            {
                if (config.DebugMode)
                {
                    if (code == 200)
                    {
                        Puts($"Heartbeat sent (Players: {BasePlayer.activePlayerList.Count}, FPS: {Performance.current.frameRate:F1})");
                    }
                    else
                    {
                        PrintWarning($"Heartbeat failed: HTTP {code}");
                    }
                }
            });
        }

        private void SendEvent(string eventType, Dictionary<string, object> data)
        {
            data["license_key"] = config.LicenseKey;

            SendApiRequest($"/api/plugin/events/{eventType}", data, (code, response) =>
            {
                if (config.DebugMode && code != 200)
                {
                    PrintWarning($"Event {eventType} failed: HTTP {code}");
                }
            });
        }

        private void SendApiRequest(string endpoint, Dictionary<string, object> data, Action<int, string> callback)
        {
            string url = config.ApiBaseUrl.TrimEnd('/') + endpoint;
            string json = JsonConvert.SerializeObject(data);

            webrequest.Enqueue(url, json, (code, response) =>
            {
                callback?.Invoke(code, response ?? "");
            }, this, RequestMethod.POST, new Dictionary<string, string>
            {
                { "Content-Type", "application/json" }
            });
        }

        #endregion

        #region Console Commands

        [Command("corrosion.status")]
        private void StatusCommand(IPlayer player, string command, string[] args)
        {
            if (!player.IsAdmin)
            {
                player.Reply("You don't have permission to use this command");
                return;
            }

            player.Reply("=== Corrosion Companion Status ===");
            player.Reply($"Version: {Version}");
            player.Reply($"License Key: {config.LicenseKey.Substring(0, Math.Min(8, config.LicenseKey.Length))}...");
            player.Reply($"API URL: {config.ApiBaseUrl}");
            player.Reply($"Heartbeat Interval: {config.HeartbeatInterval}s");
            player.Reply($"Player Events: {(config.SendPlayerEvents ? "Enabled" : "Disabled")}");
            player.Reply($"Chat Events: {(config.SendChatEvents ? "Enabled" : "Disabled")}");
            player.Reply($"Debug Mode: {(config.DebugMode ? "Enabled" : "Disabled")}");
            player.Reply($"Active Players: {BasePlayer.activePlayerList.Count}");
        }

        [Command("corrosion.checkin")]
        private void CheckinCommand(IPlayer player, string command, string[] args)
        {
            if (!player.IsAdmin)
            {
                player.Reply("You don't have permission to use this command");
                return;
            }

            player.Reply("Sending check-in to Corrosion API...");
            CheckIn();
        }

        [Command("corrosion.heartbeat")]
        private void HeartbeatCommand(IPlayer player, string command, string[] args)
        {
            if (!player.IsAdmin)
            {
                player.Reply("You don't have permission to use this command");
                return;
            }

            player.Reply("Sending heartbeat to Corrosion API...");
            SendHeartbeat();
        }

        #endregion
    }
}
