using System.Collections.Generic; //dict
using Oxide.Game.Rust.Cui;
using UnityEngine; //Vector3
using Oxide.Core.Plugins;
using Convert = System.Convert;
using System.Linq;

namespace Oxide.Plugins
{
    [Info("Map My Patrol", "BuzZ[PHOQUE] && Ads", "0.0.8")]
    [Description(
        "Adds red marker(s) on ingame map for Heli Patrol(s) position, HUD with details, and refresh on timer.")]
/*=======================================================================================================================
 *
 *
 *   20th august 2018
 *
 *	0.0.4	configfile with sound/banner/bannercolor/HUDcolor/HUDfontsize
 *	0.0.5	hud permi + hud mecha HUDlist + bannerlook
 *
 *	THANKS TO THE OXIDE/UMOD TEAM for coding quality, ideas, and time spent for the community
 *	https://umod.org/plugins/image-library to get little animation on HUD
 *
 *=======================================================================================================================*/
    public class MapMyPatrol : RustPlugin
    {
        [PluginReference] Plugin ImageLibrary;

        bool debug = false;
        int anim;
        string icondapatrol;
        private bool ConfigChanged;
        const string MapMyPatrolHUD = "mapmypatrol.hud";
        bool sound = false;
        bool bannerdisplay = false;
        string bannercolor = "0.5 0.5 0.5 0.30";
        string HUDcolor = "0.5 0.5 0.5 0.30";
        int HUDfontsize = 10;

        public Dictionary<PatrolHelicopter, MapMarkerGenericRadius> baseradius =
            new Dictionary<PatrolHelicopter, MapMarkerGenericRadius>();

        public Dictionary<PatrolHelicopter, Vector3> baseposition = new Dictionary<PatrolHelicopter, Vector3>();
        public Dictionary<PatrolHelicopter, string> basemessage = new Dictionary<PatrolHelicopter, string>();

        public Dictionary<PatrolHelicopter, PatrolHelicopterAI> baseai =
            new Dictionary<PatrolHelicopter, PatrolHelicopterAI>();

        public Dictionary<PatrolHelicopter, BaseCombatEntity> basecombat =
            new Dictionary<PatrolHelicopter, BaseCombatEntity>();

        public Dictionary<PatrolHelicopter, BaseEntity> baseent = new Dictionary<PatrolHelicopter, BaseEntity>();
        public Dictionary<string, BasePlayer> HUDlist = new Dictionary<string, BasePlayer>();

        private Timer patrolrefresh;

/*	FOR FUTURE VERSIONS
https://image.ibb.co/eCiHqK/Map_My_Patrol_icone_HUD_blue.png
https://image.ibb.co/i2RsPe/Map_My_Patrol_icone_HUD_fullgreen.png
https://image.ibb.co/dJYTxz/Map_My_Patrol_icone_HUD_fullred.png
https://image.ibb.co/npaK4e/Map_My_Patrol_icone_HUD_green.png
https://image.ibb.co/mJVmje/Map_My_Patrol_icone_HUD_purple.png
https://image.ibb.co/bYrsPe/Map_My_Patrol_icone_HUD_red.png
*/
        void Init()
        {
            LoadVariables();
            permission.RegisterPermission(MapMyPatrolHUD, this);
        }

        void OnServerInitialized()
        {
            ulong imageId = 666999666999;
            if (ImageLibrary)
            {
                bool exists = (bool)ImageLibrary?.Call("HasImage", "mapmypatrolblue", imageId);
                if (exists == false)
                {
                    ImageLibrary?.Call("AddImage",
                        "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Maki-heliport-15.svg/240px-Maki-heliport-15.svg.png",
                        "mapmypatrolblue", imageId);
                    // ImageLibrary?.Call ("AddImage","https://image.ibb.co/eCiHqK/Map_My_Patrol_icone_HUD_blue.png", "mapmypatrolblue", imageId);
                    if (debug)
                    {
                        Puts($"ADDING ICON TO ImageLibrary");
                    }
                }

                if (debug)
                {
                    Puts($"LOADING ICON from ImageLibrary");
                }

                icondapatrol = (string)ImageLibrary?.Call("GetImage", "mapmypatrolblue", imageId);
            }

            if (ImageLibrary == false)
            {
                PrintWarning($"You are missing plugin reference : ImageLibrary");
            }
        }

        void Unload()
        {
            foreach (var paire in baseradius)
            {
                paire.Value.Kill();
                paire.Value.SendUpdate();
                if (debug) Puts($"PATROL MAPMARKER KILLED");
                /*baseradius.Clear();
                basemessage.Clear();
                baseposition.Clear();
                baseai.Clear();
                basecombat.Clear();
                baseent.Clear();*/
            }

            foreach (var playerhud in HUDlist)
            {
                CuiHelper.DestroyUi(playerhud.Value, playerhud.Key);
            }
        }


        #region MESSAGES

        void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                {
                    "SpawnMsg",
                    "A Patrol has spawned and will fly above Island in a few. Check your MAP (G) for a red marker."
                },
                { "KilledMsg", "A Patrol has gone away from Island." },
            }, this, "en");

            lang.RegisterMessages(new Dictionary<string, string>
            {
                {
                    "SpawnMsg", "Une patrouille est en route pour l'île. Un marqueur rouge est rajouté sur la carte (G)"
                },
                { "KilledMsg", "Une patrouille a quitté l'île." },
            }, this, "fr");
        }

        #endregion


        #region CONFIG

        protected override void LoadDefaultConfig()
        {
            LoadVariables();
        }

        private void LoadVariables()
        {
            /*Prefix = Convert.ToString(GetConfig("Chat Settings", "Prefix", "[My CH47] "));                       // CHAT PLUGIN PREFIX
            PrefixColor = Convert.ToString(GetConfig("Chat Settings", "PrefixColor", "#149800"));                // CHAT PLUGIN PREFIX COLOR
            ChatColor = Convert.ToString(GetConfig("Chat Settings", "ChatColor", "#bbffb1"));                    // CHAT MESSAGE COLOR
            SteamIDIcon = Convert.ToUInt64(GetConfig("Chat Settings", "SteamIDIcon", "76561198332562475"));*/
            sound = Convert.ToBoolean(GetConfig("Sound Settings", "play soundfx", "false"));
            bannerdisplay = Convert.ToBoolean(GetConfig("Banner Settings", "display banner", "false"));
            HUDfontsize = Convert.ToInt32(GetConfig("HUD Settings", "font size", "10"));
            HUDcolor = Convert.ToString(GetConfig("HUD Settings", "color on 3 firsts numbers - opacity on last number",
                "0.5 0.5 0.5 0.30"));
            bannercolor = Convert.ToString(GetConfig("Banner Settings",
                "color on 3 firsts numbers - opacity on last number", "0.5 0.5 0.5 0.30"));

            if (!ConfigChanged) return;
            SaveConfig();
            ConfigChanged = false;
        }

        private object GetConfig(string menu, string datavalue, object defaultValue)
        {
            var data = Config[menu] as Dictionary<string, object>;
            if (data == null)
            {
                data = new Dictionary<string, object>();
                Config[menu] = data;
                ConfigChanged = true;
            }

            object value;
            if (!data.TryGetValue(datavalue, out value))
            {
                value = defaultValue;
                data[datavalue] = value;
                ConfigChanged = true;
            }

            return value;
        }

        #endregion


        void MarkerDisplayingDelete(PatrolHelicopter delpatrol)
        {
            if (baseradius.ContainsKey(delpatrol) == true)
            {
                MapMarkerGenericRadius delmarker;
                baseradius.TryGetValue(delpatrol, out delmarker);
                delmarker.Kill();
                delmarker.SendUpdate();
                if (debug)
                {
                    Puts($"PATROL MAPMARKER KILLED");
                }
            }
        }

        void GenerateMarkers()
        {
            if (baseradius != null)
            {
                foreach (var paire in baseradius)
                {
                    MapMarkerGenericRadius MapMarkerDel = paire.Value;
                    if (MapMarkerDel != null)
                    {
                        MapMarkerDel.Kill();
                        MapMarkerDel.SendUpdate();
                    }
                }
            }


            foreach (var nelico in baseposition)
            {
                Vector3 position = nelico.Value;
                MapMarkerGenericRadius MapMarker =
                    GameManager.server.CreateEntity("assets/prefabs/tools/map/genericradiusmarker.prefab", position) as
                        MapMarkerGenericRadius;
                MapMarker.alpha = 0.6f;
                MapMarker.color1 = Color.red;
                MapMarker.color2 = Color.black;
                MapMarker.radius = 8;
                baseradius.Remove(nelico.Key);
                baseradius.Add(nelico.Key, MapMarker);
                if (debug)
                {
                    Puts($"PATROL MARKER SPAWNED ON MAP");
                }
            }

            foreach (var paire in baseradius)
            {
                paire.Value.Spawn();
                paire.Value.SendUpdate();
            }
        }

        #region HUD

        private void PatrolHUD()
        {
            int patrolnum = basemessage.Count;
            anim = anim + 1;
            double colonnegauche = 0.00;
            colonnegauche = colonnegauche + (anim * 0.16);
            if (colonnegauche > 0.89)
            {
                anim = 0;
                colonnegauche = 0.00;
            }

            double colonnedroite = colonnegauche + 0.15;
            double lignehaut = 0.80;
            double lignebas = lignehaut - 0.10;
            int Round = 1;
            int round = -1;
            List<string> messagelist = new List<string>();
            List<PatrolHelicopter> helilist = new List<PatrolHelicopter>();
            List<PatrolHelicopterAI> ailist = new List<PatrolHelicopterAI>();
            string[] messagearray;
            PatrolHelicopter[] heliarray;
            PatrolHelicopterAI[] aiarray;
            foreach (var paire in basemessage)
            {
                messagelist.Add(paire.Value);
                helilist.Add(paire.Key);
                if (baseai.ContainsKey(paire.Key) == true)
                {
                    PatrolHelicopterAI ai;
                    baseai.TryGetValue(paire.Key, out ai);
                    ailist.Add(ai);
                }
            }

            messagearray = messagelist.ToArray();
            heliarray = helilist.ToArray();
            aiarray = ailist.ToArray();
            if (debug)
            {
                Puts($"BaseMessage COUNT : {messagelist.Count}");
            }

            for (Round = 1; Round <= patrolnum; Round++)
            {
                round = round + 1;
                double lignedecalage = 0.11 * round;
                var CuiElement = new CuiElementContainer();
                var PatrolHUDBanner = CuiElement.Add(new CuiPanel
                {
                    Image = { Color = HUDcolor },
                    RectTransform =
                    {
                        AnchorMin = $"0.0 {lignebas - lignedecalage}", AnchorMax = $"0.08 {lignehaut - lignedecalage}"
                    },
                    CursorEnabled = false
                });
                /*var closeButton = new CuiButton{Button ={Close = PatrolHUDBanner,Color = "0.0 0.0 0.0 0.6"},RectTransform ={AnchorMin = "0.90 0.00",AnchorMax = "0.99 1.00"},Text ={Text = "X",FontSize = 20,Align = TextAnchor.MiddleCenter}};
                CuiElement.Add(closeButton, PatrolHUDBanner);       */
                foreach (BasePlayer player in BasePlayer.activePlayerList.ToList())
                {
                    Vector3 basepos;
                    baseposition.TryGetValue(heliarray[round], out basepos);
                    int dist = (int)Vector3.Distance(player.transform.position, basepos);
                    string finalmessage = $": <color=orange>{dist}m.</color> away.{messagearray[round]}";
                    PatrolHelicopterAI myAI = aiarray[round];
                    if (myAI.PlayerVisible(player) == true)
                    {
                        if (debug)
                        {
                            Puts($"PLAYER {player.displayName} IS VISIBLE !");
                        }

                        finalmessage = $"{finalmessage}\n<color=red>YOU ARE VISIBLE</color>";
                    }

                    CuiElement.Add(new CuiLabel
                    {
                        Text =
                        {
                            Text = $"<color=white>#{round + 1}</color> {finalmessage}", FontSize = HUDfontsize,
                            Align = TextAnchor.MiddleLeft, Color = "0.0 0.0 0.0 1"
                        },
                        RectTransform = { AnchorMin = "0.10 0.10", AnchorMax = "0.90 0.79" }
                    }, PatrolHUDBanner);
                    if (ImageLibrary)
                    {
                        CuiElement.Add(new CuiElement
                        {
                            Name = CuiHelper.GetGuid(),
                            Parent = PatrolHUDBanner,
                            Components =
                            {
                                new CuiRawImageComponent { Png = icondapatrol },
                                new CuiRectTransformComponent
                                    { AnchorMin = $"{colonnegauche} 0.80", AnchorMax = $"{colonnedroite} 0.99" }
                            }
                        });
                    }

                    bool displayhud = permission.UserHasPermission(player.UserIDString, MapMyPatrolHUD);
                    if (displayhud)
                    {
                        CuiHelper.AddUi(player, CuiElement);
                        HUDlist.Remove(PatrolHUDBanner);
                        HUDlist.Add(PatrolHUDBanner, player);
                    }
                }
            }
        }

        private void DestroyAllUiPlease()
        {
            foreach (var playerhud in HUDlist)
            {
                CuiHelper.DestroyUi(playerhud.Value, playerhud.Key);
            }

            HUDlist.Clear();
        }

        #endregion

        #region SPAWN DETECTION

        private void OnEntitySpawned(PatrolHelicopter helicopter)
        {
            if (helicopter == null) return;
            anim = 0;
            baseent.Add(helicopter, helicopter);
            var position = helicopter.ServerPosition;
            baseposition.Remove(helicopter);
            baseposition.Add(helicopter, position);
            PatrolHelicopterAI AI = helicopter.GetComponent<PatrolHelicopterAI>();
            baseai.Add(helicopter, AI);
            basecombat.Add(helicopter, helicopter);
            //GenerateMarkers(helicopter);
            DisplayBannerToAll("spawn");
            if (debug)
            {
                Puts($"BEFORE TIMER - IN BasePosition : {baseposition.Count}");
            } // bonus info

            if (patrolrefresh == null || patrolrefresh.Destroyed)
            {
                AfterSpawn();
                if (debug)
                {
                    Puts($"TIMER IS NULL");
                }

                patrolrefresh = timer.Repeat(5f, 0, () =>
                {
                    DestroyAllUiPlease();
                    AfterSpawn();
                });
            }
        }

        #endregion


        void AfterSpawn()
        {
            if (debug)
            {
                Puts($"VOID AFTERSPAWN");
            } // bonus info

            foreach (var paire in baseent)
            {
                if (debug)
                {
                    Puts($"AI COUNT : {baseent.Count}");
                } // bonus info

                BaseEntity Entity2;
                Entity2 = paire.Value;
                PatrolHelicopter helicopter = paire.Key;
                PatrolHelicopterAI myAI;
                baseai.TryGetValue(helicopter, out myAI);
                BaseCombatEntity patrol;
                basecombat.TryGetValue(helicopter, out patrol);
                var position2 = Entity2.ServerPosition;
                if (debug)
                {
                    Puts($"ENTITY NEW POSITION : {position2} - SPEED {myAI.moveSpeed}");
                }

                baseposition.Remove(helicopter);
                baseposition.Add(helicopter, position2);
                if (debug) Puts($"Left Rockets : {myAI.numRocketsLeft}");
                if (debug) Puts($"DESTINATION : {myAI.destination}");
                if (debug) Puts($"SPAWNTIME : {myAI.spawnTime}");
                string names = "";
                string message = "";
                message =
                    $"\nSpeed : <size=11><color=cyan>{myAI.moveSpeed}</color></size>\nLeft Rockets : <size=11><color=cyan>{myAI.numRocketsLeft}</color></size>";
                basemessage.Remove(helicopter);
                basemessage.Add(helicopter, message);
            }

            PatrolHUD();
            GenerateMarkers();
        }

        #region ON PATROL KILL

        void OnEntityKill(PatrolHelicopter helicopter, HitInfo info)
        {
            if (helicopter == null) return;
            if (baseent.ContainsKey(helicopter))
            {
                DisplayBannerToAll("killed");
                MarkerDisplayingDelete(helicopter);
                baseradius.Remove(helicopter);
                basemessage.Remove(helicopter);
                baseposition.Remove(helicopter);
                baseai.Remove(helicopter);
                basecombat.Remove(helicopter);
                baseent.Remove(helicopter);
                if (baseent.Count == 0)
                {
                    DestroyAllUiPlease();
                    patrolrefresh.Destroy();
                    //patrolrefresh = null;
                    if (debug)
                    {
                        Puts($"PATROL IS NO MORE. TIMER DESTROYED");
                    }

                    baseradius.Clear();
                    basemessage.Clear();
                    baseposition.Clear();
                    baseai.Clear();
                    basecombat.Clear();
                    baseent.Clear();
                }
            }
        }

        #endregion

        #region BANNER

        void DisplayBannerToAll(string reason)
        {
            foreach (var player in BasePlayer.activePlayerList)
            {
                if (bannerdisplay)
                {
                    string message = string.Empty;
                    if (reason == "spawn") message = $"{lang.GetMessage("SpawnMsg", this, player.UserIDString)}";
                    if (reason == "killed") message = $"{lang.GetMessage("KilledMsg", this, player.UserIDString)}";
                    var CuiElement = new CuiElementContainer();
                    var PatrolBanner = CuiElement.Add(new CuiPanel
                    {
                        Image = { Color = bannercolor },
                        RectTransform = { AnchorMin = "0.0 0.85", AnchorMax = "1.0 0.88" }, CursorEnabled = false
                    });
                    var closeButton = new CuiButton
                    {
                        Button = { Close = PatrolBanner, Color = "0.0 0.0 0.0 0.6" },
                        RectTransform = { AnchorMin = "0.90 0.01", AnchorMax = "0.99 0.99" },
                        Text = { Text = "X", FontSize = 12, Align = TextAnchor.MiddleCenter }
                    };
                    CuiElement.Add(closeButton, PatrolBanner);
                    CuiElement.Add(new CuiLabel
                    {
                        Text =
                        {
                            Text = $"{message}", FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "1.0 1.0 1.0 1"
                        },
                        RectTransform = { AnchorMin = "0.10 0.10", AnchorMax = "0.90 0.90" }
                    }, PatrolBanner);

                    CuiHelper.AddUi(player, CuiElement);
                    timer.Once(12, () => { CuiHelper.DestroyUi(player, PatrolBanner); });
                    if (debug)
                    {
                        Puts($"BANNER DISPLAYING FOR PLAYER {player.displayName}");
                    }
                }

                if (sound)
                {
                    var sound = new Effect("assets/bundled/prefabs/fx/player/howl.prefab", player, 0, Vector3.zero,
                        Vector3.forward);
                    EffectNetwork.Send(sound, player.net.connection);
                    if (debug)
                    {
                        Puts($"PLAYING SOUND FOR PLAYER {player.displayName}");
                    }
                }
            }
        }

        #endregion
    }
}


/*

FOR FUTURE VERSIONS
change icon color on behaviour (red on attack/blue on visible/etc.)

    public float lastSeenTime = float.PositiveInfinity;
    public float visibleFor;
    public Vector3 destination;
    public float moveSpeed;
    public float throttleSpeed;
    public aiState _currentState;
    private Vector3 _aimTarget;
    private bool movementLockingAiming;
    private bool hasAimTarget;
    private bool aimDoorSide;
    private Vector3 _lastPos;
    private Vector3 _lastMoveDir;
    public bool isDead;
    private bool isRetiring;
    public float spawnTime;
    public float lastDamageTime;
    public List<targetinfo> _targetList = new List<targetinfo>();
    public List<MonumentInfo> _visitedMonuments;
    public float arrivalTime;
    public float lastRocketTime;

 */