using HarmonyLib;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Reflection;
using Oxide.Core.Libraries;
using Oxide.Game.Rust.Cui;
using ProtoBuf;
using UnityEngine;
using System.Linq;
using Oxide.Core.Plugins;

namespace Oxide.Plugins;

[Info("Tc Range Workbench", "Notchu", "1.0.6")]
[Description("Makes workbench available for craft in TC range")]
public class TcRangeWorkbench : CovalencePlugin
{
    private const string permName = "tcRangeWorkbench.use";

    private static HashSet<BasePlayer> _players = new HashSet<BasePlayer>();

    private static Dictionary<BuildingPrivlidge, Workbench> _privilegeWorkbenches =
        new Dictionary<BuildingPrivlidge, Workbench>();


    private void Init()
    {
        if (!permission.PermissionExists(permName))
        {
            permission.RegisterPermission(permName, this);
        }

        foreach (BasePlayer player in BasePlayer.allPlayerList)
        {
            if (CheckPermission(player.UserIDString))
            {
                _players.Add(player);
            }
        }

        foreach (var build in BaseNetworkable.serverEntities)
        {
            LoadBuildingPrivilege(build);
        }
    }


    bool LoadBuildingPrivilege(BaseNetworkable net, bool lookForAnotherWB = false, Workbench removedWorkbench = null)
    {
        if (net is not BuildingPrivlidge privilege) return false;

        Workbench highestWorkbench = null;

        foreach (var child in privilege.GetBuilding().decayEntities)
        {
            if (child is not Workbench workbench) continue;

            if (lookForAnotherWB && removedWorkbench && workbench == removedWorkbench) continue;

            if (highestWorkbench is null)
            {
                highestWorkbench = workbench;
                continue;
            }

            if (highestWorkbench.Workbenchlevel >= workbench.Workbenchlevel) continue;

            highestWorkbench = workbench;
        }

        if (highestWorkbench is null) return false;

        _privilegeWorkbenches.Add(privilege, highestWorkbench);

        return true;
    }

    private void Unload()
    {
        _privilegeWorkbenches.Clear();
        _players.Clear();
    }

    void OnPlayerConnected(BasePlayer player)
    {
        if (CheckPermission(player.UserIDString))
        {
            _players.Add(player);
        }
    }

    void OnUserPermissionRevoked(string playerId, string permission)
    {
        if (permission != permName)
            return;

        var player = BasePlayer.Find(playerId);

        if (player)
        {
            _players.Remove(player);
        }
    }

    void OnPlayerDisconnected(BasePlayer player, string reason)
    {
        _players.Remove(player);
    }

    void OnEntityKill(BuildingPrivlidge buildingPrivilege)
    {
        _privilegeWorkbenches.Remove(buildingPrivilege);
    }

    void OnEntityKill(Workbench workbench)
    {
        BuildingPrivlidge toRemove = null;

        foreach (var keychain in _privilegeWorkbenches)
        {
            if (keychain.Value == workbench)
            {
                toRemove = keychain.Key;

                break;
            }
        }

        if (toRemove == null) return;

        _privilegeWorkbenches.Remove(toRemove);

        LoadBuildingPrivilege(toRemove, true, workbench);
    }


    void OnEntitySpawned(BaseNetworkable entity)
    {
        LoadBuildingPrivilege(entity);

        if (entity is not Workbench workbench) return;

        var buildingPrivilege = workbench.GetBuildingPrivilege();
        ;

        if (buildingPrivilege == null) return;

        if (_privilegeWorkbenches.TryGetValue(buildingPrivilege, out var installedWorkbench))
        {
            if (installedWorkbench.Workbenchlevel >= workbench.Workbenchlevel) return;

            _privilegeWorkbenches[buildingPrivilege] = workbench;

            return;
        }

        _privilegeWorkbenches.Add(buildingPrivilege, workbench);
    }

    bool CheckPermission(string id)
    {
        return permission.UserHasPermission(id, permName);
    }

    private static float GetWorkbenchLevel(BasePlayer player, BuildingPrivlidge? privilege, Workbench? workbench = null)
    {
        if (!_players.Contains(player)) return 0;

        if (workbench != null)
        {
            return _privilegeWorkbenches.ContainsValue(workbench)
                ? workbench.Workbenchlevel
                : 0;
        }

        return _privilegeWorkbenches.TryGetValue(privilege!, out var value)
            ? value.Workbenchlevel
            : 0;
    }

    [HarmonyPatch(typeof(BasePlayer), "currentCraftLevel", MethodType.Getter)]
    [AutoPatch]
    public static class BasePlayerCurrentCraftLevelPatch
    {
        [HarmonyPrefix]
        public static bool Prefix(BasePlayer __instance, ref float __result)
        {
            var workbench = __instance.GetCachedCraftLevelWorkbench();

            if (workbench != null)
            {
                return true;
            }

            var buildingPrivilege = __instance.GetBuildingPrivilege();

            if (buildingPrivilege == null)
            {
                return true;
            }

            if (!buildingPrivilege.authorizedPlayers.Contains(__instance.userID))
                return true;

            var result = GetWorkbenchLevel(__instance, buildingPrivilege);
            if (result == 0) return true;

            __result = result;
            return false;
        }
    }
}