﻿using Newtonsoft.Json;
using Oxide.Core;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Tc Options", "Sapnu Puas", "1.0.8")]
    [Description("Add a code lock and loot to tc when placed")]
    public class TcOptions : RustPlugin
    {
        private const string codelockprefab = "assets/prefabs/locks/keypad/lock.code.prefab";
        private const string Prefab_CodeLock_LockEffect = "assets/prefabs/locks/keypad/effects/lock.code.lock.prefab";
        private readonly List<string> DefaultItemList = new List<string>()
        {
            "wood",
            "stones",
            "metal.fragments",
            "metal.refined",

            "building.planner",
            "hammer",
            "wiretool",
            "hosetool",
            "pipetool",
        };

        #region Hooks

        void OnServerInitialized(bool initial)
        {
            UpdateConfigValues();

            foreach (var perm in _config.Permissions)
                permission.RegisterPermission(perm.Key, this);
        }

        ItemContainer.CanAcceptResult? CanAcceptItem(ItemContainer container, Item item, int targetPos)
        {
            if (container == null || item == null)
                return null;
            if (container.entityOwner != null && container.entityOwner.OwnerID != 0)
            {
                if(container.entityOwner is not BuildingPrivlidge)
                    return null;

                if (CanStoreItem(container.entityOwner.OwnerID.ToString(), item)) return ItemContainer.CanAcceptResult.CanAccept;

               
            }
            return null;
        }

        private object OnItemFilter(Item item, StorageContainer storageContainer, int targetSlot)
        {
            if (item == null || storageContainer == null)
                return null;

            if (!(storageContainer is BuildingPrivlidge))
                return null;

            if (CanStoreItem(storageContainer.OwnerID.ToString(), item)) return true;


            return null;
        }

        void OnEntityBuilt(Planner plan, GameObject go)
        {
            BaseEntity entity = go.GetComponent<BaseEntity>();
            var player = plan.GetOwnerPlayer();

            if (player == null || entity == null) return;

            var toolCupboard = entity as BuildingPrivlidge;
            if (toolCupboard != null)
            {
                var ConfigValue = GetValues(player.UserIDString);
                if (ConfigValue == null)
                    return;

                timer.Once(0.5f, () =>
                {
                    Apply(toolCupboard, ConfigValue, player);
                });


               
            }

        }

        #endregion Hooks

        #region methods
        private bool CanStoreItem(string ownerId, Item item)
        {
            if (DefaultItemList.Contains(item.info.shortname)) return true;

            var ConfigValue = GetValues(ownerId);
            if (ConfigValue == null) return false;

            if (ConfigValue.AllowAllItems) return true;

            if (ConfigValue.AllowedItems.Contains(item.info.shortname)) return true;

            var allowedItem = ConfigValue.LootToAdd.FirstOrDefault(x => x.shortname == item.info.shortname ||
            (!string.IsNullOrEmpty(x.customName) && x.customName == item.name) ||
            (x.skin != 0 && x.skin == item.skin));

            return allowedItem != null;
        }

        private static void Apply(BuildingPrivlidge buildingPrivilege, Settings settings, BasePlayer player)
        {
            if (settings.LootToAdd.Count > 0)
            {
                PopulateItems(settings.LootToAdd, buildingPrivilege.inventory);
            }

            CodeLock codeLock = null;
            if (settings.AddLock)
            {
                codeLock = AddLock(buildingPrivilege, player);
            }
            if (settings.AuthTeam)
            {
                AuthorizeTeamOnTCAndLock(player, buildingPrivilege, codeLock);
            }
        }

        private static void PopulateItems(List<SaveItemData> items, ItemContainer itemContainer)
        {
            foreach (SaveItemData saveItemData in items)
            {
                Item newItem = ItemManager.CreateByName(saveItemData.shortname, saveItemData.amount, saveItemData.skin);
                newItem.condition = newItem.maxCondition * Mathf.Clamp01(saveItemData.condition);

                if (!string.IsNullOrEmpty(saveItemData.customName))
                    newItem.name = saveItemData.customName;


                if (!string.IsNullOrEmpty(saveItemData.noteMessage) && newItem.info.itemid == 1414245162)
                    newItem.text = saveItemData.noteMessage;

                newItem.MarkDirty();

                if (!newItem.MoveToContainer(itemContainer))
                {
                    newItem.Remove();
                    continue;
                }
                if (saveItemData.projectileData != null)
                {
                    BaseProjectile projectile = newItem.GetHeldEntity() as BaseProjectile;
                    if (projectile != null)
                    {

                        if (saveItemData.projectileData.ammoShortname != "")
                            projectile.primaryMagazine.ammoType = ItemManager.FindItemDefinition(saveItemData.projectileData.ammoShortname);

                        projectile.primaryMagazine.contents = saveItemData.projectileData.ammoAmount;
                        foreach (var weaponMod in saveItemData.projectileData.mods)
                        {
                            ItemDefinition itemDefinition = ItemManager.FindItemDefinition(weaponMod.shortname);
                            if (itemDefinition != null)
                            {
                                Item item = ItemManager.Create(itemDefinition, 1, weaponMod.skin);
                                item.condition = item.maxCondition * Mathf.Clamp01(weaponMod.condition);

                                if (weaponMod.customName != null)
                                    newItem.name = weaponMod.customName;

                                if (!item.MoveToContainer(newItem.contents))
                                {
                                    item.Remove();
                                }
                            }
                        }
                    }
                }
            }
        }

        private static CodeLock AddLock(BaseEntity container, BasePlayer player)
        {
            CodeLock codeLock = GameManager.server.CreateEntity(codelockprefab) as CodeLock;
            if (codeLock == null)
            {
                return null;  
            }
            codeLock.Spawn();
            codeLock.OwnerID = player.OwnerID;
            codeLock.code = UnityEngine.Random.Range(1111, 9999).ToString();
            codeLock.SetParent(container, container.GetSlotAnchorName(BaseEntity.Slot.Lock));
            container.SetSlot(BaseEntity.Slot.Lock, codeLock);
            codeLock.whitelistPlayers.Add(container.OwnerID);
            codeLock.SetFlag(BaseEntity.Flags.Locked, true);
            codeLock.SendNetworkUpdateImmediate();
            Effect.server.Run(Prefab_CodeLock_LockEffect, codeLock, 0, Vector3.zero, Vector3.forward);
            return codeLock;
        }

        private static void AuthorizeTeamOnTCAndLock(BasePlayer player, BuildingPrivlidge tc, CodeLock codeLock = null)
        {
            if (player == null)
                return;

           
            if (tc == null)
                return;

            var team = player.Team;
            var members = team?.members ?? new List<ulong> { player.userID };

            foreach (var memberId in members)
            {
                var member = BasePlayer.FindByID(memberId);
                if (member == null)
                    continue;

                // --- Authorize on TC ---
                if (tc.authorizedPlayers.All(x => x != member.userID))
                {
                    tc.authorizedPlayers.Add(member.userID);
                }

                // --- Whitelist on CodeLock (if found) ---
                if (codeLock != null && !codeLock.whitelistPlayers.Contains(member.userID))
                {
                    codeLock.whitelistPlayers.Add(member.userID);
                }
            }

           
            tc.SendNetworkUpdate();
            codeLock?.SendNetworkUpdate();
        }

        #endregion Methods

        #region Config

        private PluginConfig _config;
        public Settings GetValues(string ownerid)
        {
            string Permission = "";
            foreach (var check in _config.Permissions)
            {
                if (permission.UserHasPermission(ownerid, check.Key))
                {
                    Permission = check.Key;
                }
            }
            if (string.IsNullOrEmpty(Permission))
                return null;
            var playerPermission = _config.Permissions[Permission];
            if (playerPermission != null)
            {
                return playerPermission;
            }
            return null;
        }

        protected override void LoadDefaultConfig()=> _config = PluginConfig.DefaultConfig();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            _config = Config.ReadObject<PluginConfig>();
            Config.WriteObject(_config, true);
        }

        protected override void SaveConfig() => Config.WriteObject(_config);

        private void UpdateConfigValues()
        {
            if (_config.version != Version)
            {
                PluginConfig defaultConfig = PluginConfig.DefaultConfig();

                if (_config.version < new VersionNumber(1, 0, 7))
                {
                    _config.Permissions.TryAdd($"{nameof(TcOptions)}.noteexample", new Settings
                    {
                        AddLock = true,
                        AuthTeam = true,
                        AllowAllItems = true,
                        LootToAdd = new List<SaveItemData>
                        {
                             new SaveItemData
                             {
                                 shortname = "note",
                                 customName = "Some note",
                                 noteMessage = "put the notes message here",
                                 amount = 1,
                                 skin = 0,
                                 condition = 1,
                             },
                        }
                    });
                }
                Debug.Log($"Updating config from {_config.version} to {Version} ");
                _config.version = Version;
                SaveConfig();
            }
        }

        public class PluginConfig
        {
            [JsonProperty("Permissions", ObjectCreationHandling = ObjectCreationHandling.Replace)]
            public Dictionary<string, Settings> Permissions = new Dictionary<string, Settings>();

            [JsonProperty("Config version. Dont edit")] public VersionNumber version;
            public static PluginConfig DefaultConfig()
            {
                return new PluginConfig()
                {
                    Permissions = new Dictionary<string, Settings>()
                    {
                        [$"{nameof(TcOptions)}.customexample"] = new Settings()
                        {
                            AddLock = true,
                            AuthTeam = true,
                            AllowAllItems = true,
                            LootToAdd = new List<SaveItemData>
                            {
                                 new SaveItemData
                                 {
                                     shortname = "wood",
                                     customName = "",
                                     amount = 2000,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "stones",
                                     customName = "",
                                     amount = 3000,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "metal.fragments",
                                     customName = "",
                                     amount = 1000,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "metal.refined",
                                     customName = "",
                                     amount = 100,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "glue",
                                     customName = "Super fuel",
                                     amount = 500,
                                     skin = 2664651800,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "paper",
                                     customName = "Money",
                                     amount = 8000,
                                     skin = 2420097877,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "advancedblueprintfragment",
                                     customName = "",
                                     amount = 7,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "rifle.ak",
                                     customName = "",
                                     amount = 1,
                                     skin = 3512805473,
                                     condition = 1,
                                     projectileData = new ProjectileData
                                     {
                                         ammoShortname = "ammo.rifle",
                                         ammoAmount = 38,
                                         mods = new List<WeaponMod>
                                         {
                                             new WeaponMod
                                             {
                                                 shortname = "weapon.mod.holosight",
                                                 customName = "",
                                                 skin = 0,
                                                 condition = 1,
                                             },
                                             new WeaponMod
                                             {
                                                 shortname = "weapon.mod.silencer",
                                                 customName = "",
                                                 skin = 0,
                                                 condition = 1f,
                                             },
                                             new WeaponMod
                                             {
                                                 shortname = "weapon.mod.extendedmags",
                                                 customName = "",
                                                 skin = 0,
                                                 condition = 1,
                                             },
                                             new WeaponMod
                                             {
                                                 shortname = "weapon.mod.lasersight",
                                                 customName = "",
                                                 skin = 0,
                                                 condition = 1,
                                             },
                                         }
                                     }
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "rifle.ak.diver",
                                     customName = "",
                                     amount = 1,
                                     skin = 0,
                                     condition = 1,
                                     projectileData = new ProjectileData
                                     {
                                         ammoShortname = "ammo.rifle",
                                         ammoAmount = 30,
                                         mods = new List<WeaponMod>
                                         {
                                             new WeaponMod
                                             {
                                                 shortname = "weapon.mod.holosight",
                                                 customName = "",
                                                 skin = 0,
                                                 condition = 1,
                                             },
                                             new WeaponMod
                                             {
                                                 shortname = "weapon.mod.silencer",
                                                 customName = "",
                                                 skin = 0,
                                                 condition = 1f,
                                             },
                                             new WeaponMod
                                             {
                                                 shortname = "weapon.mod.lasersight",
                                                 customName = "",
                                                 skin = 0,
                                                 condition = 1,
                                             },
                                         }
                                     }
                                 },
                            }
                        },
                        [$"{nameof(TcOptions)}.vip"] = new Settings()
                        {
                            AddLock = true,
                            AuthTeam = true,
                            LootToAdd = new List<SaveItemData>
                            {
                                 
                                 new SaveItemData
                                 {
                                     shortname = "wood",
                                     customName = "",
                                     amount = 10000,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "stones",
                                     customName = "",
                                     amount = 10000,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "metal.fragments",
                                     customName = "",
                                     amount = 10000,
                                     skin = 0,
                                     condition = 1,
                                 }
                            }
                        },
                        [$"{nameof(TcOptions)}.vip2"] = new Settings()
                        {
                            AddLock = true,
                            AuthTeam = true,
                            LootToAdd = new List<SaveItemData>
                            {
                                 
                                 new SaveItemData
                                 {
                                     shortname = "wood",
                                     customName = "",
                                     amount = 50000,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "stones",
                                     customName = "",
                                     amount = 80000,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "metal.fragments",
                                     customName = "",
                                     amount = 70000,
                                     skin = 0,
                                     condition = 1,
                                 },
                                 new SaveItemData
                                 {
                                     shortname = "advancedblueprintfragment",
                                     customName = "",
                                     amount = 7,
                                     skin = 0,
                                     condition = 1,
                                 }
                            },

                            AllowedItems = new List<string>
                            {
                                "sulfur",
                                "sulfur.ore"
                            }
                        },
                    },
                    version = new VersionNumber(1, 0, 6),
                };
            }
        }

        public class Settings
        {
            [JsonProperty("Add Codelock ?")] public bool AddLock = true;
            [JsonProperty("Auto auth all team members ?")] public bool AuthTeam = false;
            [JsonProperty("Loot to add")] public List<SaveItemData> LootToAdd = new List<SaveItemData>();
            [JsonProperty("Allow All Items to be stored inside")] public bool AllowAllItems =false;
            [JsonProperty("Extra Allowed items that can be stored inside")] public List<string> AllowedItems = new List<string>();
        }

        public class SaveItemData
        {
            [JsonProperty("item short name")] public string shortname;
            [JsonProperty("item custom name")] public string customName;
            [JsonProperty("note message. only used if item is a note")] public string noteMessage;
            [JsonProperty("item amount")] public int amount;
            [JsonProperty("item skinid")] public ulong skin;
            [JsonProperty("item condition (percent 0.5 = half 1 = max)")] public float condition;
            [JsonProperty("projectile data. only used if item is a gun")] public ProjectileData projectileData = null;
           
        }

        public class ProjectileData
        {
            [JsonProperty("ammo short name")] public string ammoShortname;
            [JsonProperty("ammo amount")] public int ammoAmount;
            [JsonProperty("weapon attachments")] public List<WeaponMod> mods = new List<WeaponMod>();
        }

        public class WeaponMod
        {
            [JsonProperty("item short name")] public string shortname;
            [JsonProperty("item custom name")] public string customName;
            [JsonProperty("item skinid")] public ulong skin;
            [JsonProperty("item condition (percent 0.5 = half 1 = max)")] public float condition;
        }

        #endregion Config
    }
}