﻿using System;
using System.IO;
using Oxide.Core;
using System.Linq;
using Newtonsoft.Json;
using System.Collections.Generic;

namespace Oxide.Plugins
{
    [Info("Block Items", "klauz24", "1.0.2"), Description("Allows to block usage/crafting of certain items permanently or temporary.")]
    internal class BlockItems : HurtworldPlugin
    {
        private DateTime _dt;

        private Configuration _config;

        private const string _perm = "blockitems.bypass";

        private class BlockedItem
        {
            public bool CanBeCrafted;
            public bool CanBeUsed;
            public string Note;
            public string ItemGuid;
            public string RealTimeDateTime;
            public int FixedTimeSeconds;
        }

        private class Configuration
        {
            [JsonProperty(PropertyName = "PermanentBlock")]
            public List<string> PermBlockedList { get; set; } = new List<string>()
            {
                "Some GUID here"
            };

            [JsonProperty(PropertyName = "TemporaryBlock")]
            public TemporaryBlock TempBlock = new TemporaryBlock();

            public class TemporaryBlock
            {
                public bool UseFixedTime = false;
                public string FixedTime = GetNicelyFormattedDateTime(DateTime.Now);
                public List<BlockedItem> TempBlockedFixedTimeList = new List<BlockedItem>()
                {
                    new BlockedItem()
                    {
                        CanBeCrafted = false,
                        CanBeUsed = false,
                        Note = "Some note here for easier filtering",
                        ItemGuid = "Some GUID here",
                        RealTimeDateTime = "",
                        FixedTimeSeconds = 3600
                    }
                };
                public List<BlockedItem> TempBlockedRealTimeList = new List<BlockedItem>()
                {
                    new BlockedItem()
                    {
                        CanBeCrafted = false,
                        CanBeUsed = false,
                        Note = "Some note here for easier filtering",
                        ItemGuid = "Some GUID here",
                        RealTimeDateTime = GetNicelyFormattedDateTime(DateTime.Now),
                        FixedTimeSeconds = 0
                    }
                };
            }
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if (_config == null)
                {
                    throw new JsonException();
                }
            }
            catch
            {
                string configPath = $"{Interface.Oxide.ConfigDirectory}{Path.DirectorySeparatorChar}{Name}";
                PrintWarning($"Could not load a valid configuration file, creating a new configuration file at {configPath}.json");
                Config.WriteObject(_config, false, $"{configPath}_invalid.json");
                LoadDefaultConfig();
                SaveConfig();
            }
        }

        protected override void LoadDefaultConfig() => _config = new Configuration();

        protected override void SaveConfig() => Config.WriteObject(_config);

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                {"Prefix", "<color=red>[Block Items]</color>"},
                {"TempBlocked", "This item is blocked for next {0}d. {1}h. {2}m. {3}s."},
                {"PermBlocked", "This item is permantly blocked on this server."}
            }, this);
        }

        private void OnServerInitialized() => _dt = GetDateTime(_config.TempBlock.FixedTime);

        private void Init() => permission.RegisterPermission(_perm, this);

        private object CanCraft(Crafter crafter, PlayerSession session, ICraftable recipe, int count)
        {
            var item = recipe.GenerateItem();
            if (item != null && IsItemBlocked(session, item, true))
            {
                return false;
            }
            return null;
        }

        private void OnItemSelected(ItemObject item, EquippedHandlerServer player)
        {
            var session = GetPlayerSession(player);
            if (session != null && IsItemBlocked(session, item, false))
            {
                player.TryUnEquipItem();
            }
        }

        private bool IsItemBlocked(PlayerSession session, ItemObject item, bool isCrafting)
        {
            if (!HasPerm(session, _perm))
            {
                var itemGuid = GetGuid(item);
                var permBlockedItem = _config.PermBlockedList.Where(x => x == itemGuid).FirstOrDefault();
                if (permBlockedItem != null)
                {
                    Message(session, Lang(session, "PermBlocked"));
                    return true;
                }
                else
                {
                    var blockedItem = GetBlockedItem(itemGuid);
                    if (blockedItem != null)
                    {
                        if (!CanBeCraftedOrUsed(blockedItem, isCrafting))
                        {
                            if (blockedItem.FixedTimeSeconds > 0)
                            {
                                if (IsItemBlockedLate(session, blockedItem, blockedItem.FixedTimeSeconds))
                                {
                                    return true;
                                }

                            }
                            else
                            {
                                if (IsItemBlockedLate(session, blockedItem))
                                {
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }

        private bool IsItemBlockedLate(PlayerSession session, BlockedItem item, int value = 0)
        {
            TimeSpan ts;
            if (value > 0)
            {
                ts = _dt.AddSeconds(value).Subtract(DateTime.Now);
            }
            else
            {
                ts = GetDateTime(item.RealTimeDateTime).Subtract(DateTime.Now);
            }
            if (ts.TotalSeconds > 0)
            {
                Message(session, string.Format(Lang(session, "TempBlocked"), ts.Days, ts.Hours, ts.Minutes, ts.Seconds));
                return true;
            }
            return false;
        }

        private bool CanBeCraftedOrUsed(BlockedItem item, bool isCrafting)
        {
            if (isCrafting)
            {
                if (item.CanBeCrafted)
                {
                    return true;
                }
            }
            else
            {
                if (item.CanBeUsed)
                {
                    return true;
                }
            }
            return false;
        }

        private BlockedItem GetBlockedItem(string guid)
        {
            var fixedTimeBlocked = _config.TempBlock.TempBlockedFixedTimeList.Where(x => x.ItemGuid == guid).FirstOrDefault();
            if (fixedTimeBlocked != null)
            {
                return fixedTimeBlocked;
            }
            else
            {
                var realTimeBlocked = _config.TempBlock.TempBlockedRealTimeList.Where(x => x.ItemGuid == guid).FirstOrDefault();
                if (realTimeBlocked != null)
                {
                    return realTimeBlocked;
                }
            }
            return null;
        }

        private PlayerSession GetPlayerSession(EquippedHandlerServer handler) => GameManager.Instance.GetSession(handler.HNetworkView().owner);

        private DateTime GetDateTime(string str) => Convert.ToDateTime(str);

        private static string GetNicelyFormattedDateTime(DateTime dt) => dt.ToString("g");

        private string GetGuid(ItemObject obj) => RuntimeHurtDB.Instance.GetGuid(obj.Generator);

        private bool HasPerm(PlayerSession session, string perm) => permission.UserHasPermission(session.SteamId.ToString(), perm);

        private string Lang(PlayerSession session, string key) => lang.GetMessage(key, this, session.SteamId.ToString());

        private void Message(PlayerSession session, string message) => hurt.SendChatMessage(session, Lang(session, "Prefix"), message);
    }
}