using Newtonsoft.Json;
using Oxide.Core;
using System;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Heli Editor", "Mabel", "1.0.1")]
    [Description("Modify several characteristics of aircrafts")]
    class HeliEditor : RustPlugin
    {
        #region Fields
        static Configuration config;
        string permissionTakeoff = "helieditor.takeoff";
        #endregion

        #region Config
        public class PermissionSettings
        {
            [JsonProperty(PropertyName = "Use Permission For Instant Takeoff")] public bool useInstantTakeoffPermission;
        }

        public class HelicopterSettings
        {
            [JsonProperty(PropertyName = "Max Health")] public float maxHealth;
            [JsonProperty(PropertyName = "Invincible")] public bool invincible;
            [JsonProperty(PropertyName = "Block Explosions")] public bool blockExplosions;
            [JsonProperty(PropertyName = "Instant Takeoff")] public bool instantTakeoff;
            [JsonProperty(PropertyName = "Hydrophobic")] public bool hydrophobic;
        }

        public class Configuration
        {
            [JsonProperty(PropertyName = "Permission Settings")] public PermissionSettings permissionSettings;
            [JsonProperty(PropertyName = "Minicopter Settings")] public HelicopterSettings miniCopter;
            [JsonProperty(PropertyName = "Scrap Helicopter Settings")] public HelicopterSettings scrapHeli;
            [JsonProperty(PropertyName = "Attack Helicopter Settings")] public HelicopterSettings attackHeli;
            public VersionNumber Version;

            public static Configuration DefaultConfig()
            {
                return new Configuration
                {
                    permissionSettings = new PermissionSettings()
                    {
                        useInstantTakeoffPermission = true
                    },
                    miniCopter = new HelicopterSettings()
                    {
                        maxHealth = 750f,
                        invincible = false,
                        blockExplosions = false,
                        instantTakeoff = false,
                        hydrophobic = false
                    },
                    scrapHeli = new HelicopterSettings()
                    {
                        maxHealth = 1000f,
                        invincible = false,
                        blockExplosions = false,
                        instantTakeoff = false,
                        hydrophobic = false
                    },
                    attackHeli = new HelicopterSettings()
                    {
                        maxHealth = 850f,
                        invincible = false,
                        blockExplosions = false,
                        instantTakeoff = false,
                        hydrophobic = false
                    },
                    Version = default(VersionNumber)
                };
            }
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();

            try
            {
                config = Config.ReadObject<Configuration>();

                bool isNewConfig = config.Version == default(VersionNumber);

                if (!isNewConfig && config.Version < Version)
                {
                    UpdateConfig();
                }

                config.Version = Version;
                SaveConfig();
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);
                PrintError($"Failed to load configuration: {ex.Message}");
            }
        }

        protected override void LoadDefaultConfig() => config = Configuration.DefaultConfig();
        protected override void SaveConfig() => Config.WriteObject(config);

        void UpdateConfig()
        {
            PrintWarning("Config update detected! Updating config values...");

            Configuration baseConfig = Configuration.DefaultConfig();
            if (config.Version < new VersionNumber(1, 0, 0))
                config = baseConfig;

            config.Version = Version;
            PrintWarning("Config update completed!");
        }
        #endregion

        #region Hooks
        void Init()
        {
            permission.RegisterPermission(permissionTakeoff, this);
        }

        void OnServerInitialized()
        {
            foreach (var entity in BaseNetworkable.serverEntities)
            {
                if (entity is PlayerHelicopter helicopter)
                {
                    OnEntitySpawned(helicopter);
                }
            }
        }

        object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null || info == null) return null;

            bool invincible =
                (entity is Minicopter && config.miniCopter.invincible) ||
                (entity is ScrapTransportHelicopter && config.scrapHeli.invincible) ||
                (entity is AttackHelicopter && config.attackHeli.invincible);

            if (!invincible) return null;
            info.damageTypes.Clear();
            return true;
        }

        void OnEntitySpawned(BaseHelicopter helicopter)
        {
            switch (helicopter)
            {
                case Minicopter mini:
                    ApplySettings(mini, config.miniCopter);
                    break;

                case ScrapTransportHelicopter scrap:
                    ApplySettings(scrap, config.scrapHeli);
                    break;

                case AttackHelicopter attack:
                    ApplySettings(attack, config.attackHeli);
                    break;
            }
        }

        void OnEngineStarted(BaseVehicle vehicle, BasePlayer driver)
        {
            if (driver == null) return;

            if (config.permissionSettings.useInstantTakeoffPermission && !permission.UserHasPermission(driver.UserIDString, permissionTakeoff)) return;

            switch (vehicle)
            {
                case Minicopter mini when config.miniCopter.instantTakeoff:
                    mini.engineController?.FinishStartingEngine();
                    break;

                case ScrapTransportHelicopter scrap when config.scrapHeli.instantTakeoff:
                    scrap.engineController?.FinishStartingEngine();
                    break;

                case AttackHelicopter attack when config.attackHeli.instantTakeoff:
                    attack.engineController?.FinishStartingEngine();
                    break;
            }
        }
        #endregion

        #region Helpers
        void ApplySettings(PlayerHelicopter helicopter, HelicopterSettings settings)
        {
            if (settings.blockExplosions)
            {
                helicopter.explosionEffect.guid = null;
                helicopter.serverGibs.guid = null;
                helicopter.fireBall.guid = null;
            }

            helicopter.SetMaxHealth(settings.maxHealth);
            helicopter.health = settings.maxHealth;

            if (settings.hydrophobic && helicopter.waterSample != null)
            {
                helicopter.waterSample.transform.SetParent(null);
                helicopter.waterSample.position = new Vector3(1000f, 1000f, 1000f);
            }

            if (settings.invincible)
            {
                helicopter.killTriggers = Array.Empty<GameObject>();
            }
        }
        #endregion
    }
}