using GTANetworkAPI;
using ReallifeGamemode.Server.Entities;
using ReallifeGamemode.Server.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Timers;

namespace ReallifeGamemode.Server.Managers
{
    public class VehicleManager
    {
        private static readonly List<string> _enabledMods = new List<string>()
        {
            "ninef",
            "ninef2",
            "blista",
            "asea",
            "asea2",
            "boattrailer",
            "bus",
            "armytanker",
            "armytrailer",
            "armytrailer2",
            "freighttrailer",
            "coach",
            "airbus",
            "asterope",
            "airtug",
            "ambulance",
            "barracks",
            "barracks2",
            "baller",
            "baller2",
            "bjxl",
            "banshee",
            "benson",
            "bfinjection",
            "biff",
            "blazer",
            "blazer2",
            "blazer3",
            "bison",
            "bison2",
            "bison3",
            "boxville",
            "boxville2",
            "boxville3",
            "bobcatxl",
            "bodhi2",
            "buccaneer",
            "buffalo",
            "buffalo2",
            "bulldozer",
            "bullet",
            "blimp",
            "burrito",
            "burrito2",
            "burrito3",
            "burrito4",
            "burrito5",
            "cavalcade",
            "cavalcade2",
            "policet",
            "gburrito",
            "cablecar",
            "caddy",
            "caddy2",
            "camper",
            "carbonizzare",
            "cheetah",
            "comet2",
            "cogcabrio",
            "coquette",
            "cutter",
            "gresley",
            "dilettante",
            "dilettante2",
            "dune",
            "dune2",
            "hotknife",
            "dloader",
            "dubsta",
            "dubsta2",
            "dump",
            "rubble",
            "docktug",
            "dominator",
            "emperor",
            "emperor2",
            "emperor3",
            "entityxf",
            "exemplar",
            "elegy2",
            "f620",
            "fbi",
            "fbi2",
            "felon",
            "felon2",
            "feltzer2",
            "firetruk",
            "flatbed",
            "forklift",
            "fq2",
            "fusilade",
            "fugitive",
            "futo",
            "granger",
            "gauntlet",
            "habanero",
            "hauler",
            "handler",
            "infernus",
            "ingot",
            "intruder",
            "issi2",
            "Jackal",
            "journey",
            "jb700",
            "khamelion",
            "landstalker",
            "lguard",
            "manana",
            "mesa",
            "mesa2",
            "mesa3",
            "crusader",
            "minivan",
            "mixer",
            "mixer2",
            "monroe",
            "mower",
            "mule",
            "mule2",
            "oracle",
            "oracle2",
            "packer",
            "patriot",
            "pbus",
            "penumbra",
            "peyote",
            "phantom",
            "phoenix",
            "picador",
            "pounder",
            "police",
            "police4",
            "police2",
            "police3",
            "policeold1",
            "policeold2",
            "pony",
            "pony2",
            "prairie",
            "pranger",
            "premier",
            "primo",
            "proptrailer",
            "rancherxl",
            "rancherxl2",
            "rapidgt",
            "rapidgt2",
            "radi",
            "ratloader",
            "rebel",
            "regina",
            "rebel2",
            "rentalbus",
            "ruiner",
            "rumpo",
            "rumpo2",
            "rhino",
            "riot",
            "ripley",
            "rocoto",
            "romero",
            "sabregt",
            "sadler",
            "sadler2",
            "sandking",
            "sandking2",
            "schafter2",
            "schwarzer",
            "scrap",
            "seminole",
            "sentinel",
            "sentinel2",
            "zion",
            "zion2",
            "serrano",
            "sheriff",
            "sheriff2",
            "speedo",
            "speedo2",
            "stanier",
            "stinger",
            "stingergt",
            "stockade",
            "stockade3",
            "stratum",
            "sultan",
            "superd",
            "surano",
            "surfer",
            "surfer2",
            "surge",
            "taco",
            "tailgater",
            "taxi",
            "trash",
            "tractor",
            "tractor2",
            "tractor3",
            "graintrailer",
            "baletrailer",
            "tiptruck",
            "tiptruck2",
            "tornado",
            "tornado2",
            "tornado3",
            "tornado4",
            "tourbus",
            "towtruck",
            "towtruck2",
            "utillitruck",
            "utillitruck2",
            "utillitruck3",
            "voodoo2",
            "washington",
            "stretch",
            "youga",
            "ztype",
            "sanchez",
            "sanchez2",
            "scorcher",
            "tribike",
            "tribike2",
            "tribike3",
            "fixter",
            "cruiser",
            "BMX",
            "policeb",
            "akuma",
            "carbonrs",
            "bagger",
            "bati",
            "bati2",
            "ruffian",
            "daemon",
            "double",
            "pcj",
            "vader",
            "vigero",
            "faggio2",
            "hexer",
            "annihilator",
            "buzzard",
            "buzzard2",
            "cargobob",
            "cargobob2",
            "cargobob3",
            "skylift",
            "polmav",
            "maverick",
            "nemesis",
            "frogger",
            "frogger2",
            "cuban800",
            "duster",
            "stunt",
            "mammatus",
            "jet",
            "shamal",
            "luxor",
            "titan",
            "lazer",
            "cargoplane",
            "squalo",
            "marquis",
            "dinghy",
            "dinghy2",
            "jetmax",
            "predator",
            "tropic",
            "seashark",
            "seashark2",
            "submersible",
            "freightcar",
            "freight",
            "freightcont1",
            "freightcont2",
            "freightgrain",
            "tankercar",
            "metrotrain",
            "docktrailer",
            "trailers",
            "trailers2",
            "trailers3",
            "tvtrailer",
            "raketrailer",
            "tanker",
            "trailerlogs",
            "tr2",
            "tr3",
            "tr4",
            "trflat",
            "trailersmall",
            "velum",
            "adder",
            "voltic",
            "vacca",
            "suntrap",
            "submersible2",
            "dukes",
            "dukes2",
            "buffalo3",
            "dominator2",
            "dodo",
            "marshall",
            "blimp2",
            "gauntlet2",
            "stalion",
            "stalion2",
            "blista2",
            "blista3",
            "bifta",
            "speeder",
            "kalahari",
            "paradise",
            "btype",
            "jester",
            "turismor",
            "alpha",
            "vestra",
            "zentorno",
            "massacro",
            "huntley",
            "thrust",
            "rhapsody",
            "warrener",
            "blade",
            "glendale",
            "panto",
            "dubsta3",
            "pigalle",
            "monster",
            "sovereign",
            "innovation",
            "hakuchou",
            "furoregt",
            "miljet",
            "besra",
            "coquette2",
            "swift",
            "jester2",
            "massacro2",
            "ratloader2",
            "slamvan",
            "mule3",
            "velum2",
            "tanker2",
            "casco",
            "boxville4",
            "hydra",
            "insurgent",
            "insurgent2",
            "gburrito2",
            "technical",
            "dinghy3",
            "savage",
            "enduro",
            "guardian",
            "lectro",
            "kuruma",
            "kuruma2",
            "trash2",
            "barracks3",
            "valkyrie",
            "slamvan2",
            "swift2",
            "luxor2",
            "feltzer3",
            "osiris",
            "virgo",
            "windsor",
            "coquette3",
            "vindicator",
            "t20",
            "brawler",
            "toro",
            "chino",
            "faction",
            "faction2",
            "moonbeam",
            "moonbeam2",
            "primo2",
            "chino2",
            "buccaneer2",
            "voodoo",
            "Lurcher",
            "btype2",
            "verlierer2",
            "nightshade",
            "mamba",
            "limo2",
            "schafter3",
            "schafter4",
            "schafter5",
            "schafter6",
            "cog55",
            "cog552",
            "cognoscenti",
            "cognoscenti2",
            "baller3",
            "baller4",
            "baller5",
            "baller6",
            "toro2",
            "seashark3",
            "dinghy4",
            "tropic2",
            "speeder2",
            "cargobob4",
            "supervolito",
            "supervolito2",
            "valkyrie2",
            "tampa",
            "sultanrs",
            "banshee2",
            "btype3",
            "faction3",
            "minivan2",
            "sabregt2",
            "slamvan3",
            "tornado5",
            "virgo2",
            "virgo3",
            "nimbus",
            "xls",
            "xls2",
            "seven70",
            "fmj",
            "bestiagts",
            "pfister811",
            "brickade",
            "rumpo3",
            "volatus",
            "prototipo",
            "reaper",
            "tug",
            "windsor2",
            "lynx",
            "gargoyle",
            "tyrus",
            "sheava",
            "omnis",
            "le7b",
            "contender",
            "trophytruck",
            "trophytruck2",
            "rallytruck",
            "cliffhanger",
            "bf400",
            "tropos",
            "brioso",
            "tampa2",
            "tornado6",
            "faggio3",
            "faggio",
            "raptor",
            "vortex",
            "avarus",
            "sanctus",
            "youga2",
            "hakuchou2",
            "nightblade",
            "chimera",
            "esskey",
            "wolfsbane",
            "zombiea",
            "zombieb",
            "defiler",
            "daemon2",
            "ratbike",
            "shotaro",
            "manchez",
            "blazer4",
            "elegy",
            "tempesta",
            "italigtb",
            "italigtb2",
            "nero",
            "nero2",
            "specter",
            "specter2",
            "diablous",
            "diablous2",
            "blazer5",
            "ruiner2",
            "dune4",
            "dune5",
            "phantom2",
            "voltic2",
            "penetrator",
            "boxville5",
            "wastelander",
            "technical2",
            "fcr",
            "fcr2",
            "comet3",
            "ruiner3",
            "turismo2",
            "infernus2",
            "gp1",
            "ruston",
            "trailers4",
            "xa21",
            "caddy3",
            "vagner",
            "phantom3",
            "nightshark",
            "cheetah2",
            "torero",
            "hauler2",
            "trailerlarge",
            "technical3",
            "insurgent3",
            "apc",
            "tampa3",
            "dune3",
            "trailersmall2",
            "halftrack",
            "ardent",
            "oppressor",
            "vigilante",
            "bombushka",
            "alphaz1",
            "seabreeze",
            "tula",
            "havok",
            "hunter",
            "microlight",
            "rogue",
            "pyro",
            "howard",
            "mogul",
            "starling",
            "nokota",
            "molotok",
            "rapidgt3",
            "retinue",
            "cyclone",
            "visione",
            "z190",
            "viseris",
            "comet5",
            "raiden",
            "riata",
            "sc1",
            "autarch",
            "savestra",
            "gt500",
            "comet4",
            "neon",
            "sentinel3",
            "khanjali",
            "barrage",
            "volatol",
            "akula",
            "deluxo",
            "stromberg",
            "chernobog",
            "riot2",
            "avenger",
            "avenger2",
            "thruster",
            "yosemite",
            "hermes",
            "hustler",
            "streiter",
            "revolter",
            "pariah",
            "kamacho",
            "entity2",
            "cheburek",
            "jester3",
            "caracara",
            "hotring",
            "seasparrow",
            "flashgt",
            "ellie",
            "michelli",
            "fagaloa",
            "dominator3",
            "tyrant",
            "tezeract",
            "gb200",
            "issi3",
            "taipan",
            "blimp3",
            "mule4",
            "pounder2",
            "speedo4",
            "pbus2",
            "patriot2",
            "swinger",
            "terbyte",
            "oppressor2",
            "strikeforce",
            "menacer",
            "scramjet",
            "freecrawler",
            "stafford",
            "bruiser",
            "bruiser2",
            "bruiser3",
            "brutus",
            "brutus2",
            "brutus3",
            "cerberus",
            "cerberus2",
            "cerberus3",
            "clique",
            "deathbike",
            "deathbike2",
            "deathbike3",
            "deveste",
            "deviant",
            "dominator4",
            "dominator5",
            "dominator6",
            "impaler",
            "impaler2",
            "impaler3",
            "impaler4",
            "imperator",
            "imperator2",
            "imperator3",
            "issi4",
            "issi5",
            "issi6",
            "italigto",
            "monster3",
            "monster4",
            "monster5",
            "rcbandito",
            "scarab",
            "scarab2",
            "scarab3",
            "schlagen",
            "slamvan4",
            "slamvan5",
            "slamvan6",
            "toros",
            "tulip",
            "vamos",
            "zr380",
            "zr3802",
            "zr3803",
            "streiter2",
            "polamggtr",
            "s63w222"
        };

        private static readonly Dictionary<int, NetHandle> _serverVehicles = new Dictionary<int, NetHandle>();

        private static readonly Dictionary<NetHandle, Vector3> lastPositions = new Dictionary<NetHandle, Vector3>();
        private static DateTime lastSave = DateTime.UtcNow;

        public static void StartTimer()
        {
            Timer timer = new Timer(500);
            timer.Elapsed += VehicleTimerTick;
            timer.Start();

            foreach(var name in _enabledMods)
            {
                if(_enabledMods.Where(x => x == name).Count() != 1)
                {
                    NAPI.Util.ConsoleOutput($"{name} double");
                }
            }
        }

        private static void VehicleTimerTick(object sender, ElapsedEventArgs e)
        {
            NAPI.Pools.GetAllVehicles().ForEach(v =>
            {
                Vector3 lastPosition = v.Position;
                if (lastPositions.ContainsKey(v.Handle)) lastPosition = lastPositions[v.Handle];

                double distanceDriven = v.HasSharedData("drivenDistance") ? (double)v.GetSharedData("drivenDistance") : 0D;

                double distance = lastPosition.DistanceTo(v.Position) / 1000.0;
                if (distance > 0.2) return;
                distanceDriven += distance;

                v.SetSharedData("drivenDistance", (float)distanceDriven);

                lastPositions[v.Handle] = v.Position;
            });

            if (DateTime.UtcNow.Subtract(lastSave).Seconds >= 30)
            {
                lastSave = DateTime.UtcNow;
                // save to db
                using (var dbContext = new DatabaseContext())
                {
                    foreach (var key in lastPositions.Keys.ToList())
                    {
                        Vehicle v = key.Entity<Vehicle>();
                        if (!v.HasSharedData("drivenDistance")) continue;

                        ServerVehicle sVeh = VehicleManager.GetServerVehicleFromVehicle(v, dbContext);

                        if (sVeh == null) continue;

                        sVeh.DistanceDriven = (float)v.GetSharedData("drivenDistance");

                    }
                    dbContext.SaveChanges();
                }
            }
        }

        public static void AddVehicle(ServerVehicle serverVehicle, Vehicle vehicle)
        {
            if (_serverVehicles.ContainsKey(serverVehicle.Id))
            {
                return;
            }

            if (_serverVehicles.ContainsValue(vehicle.Handle))
            {
                return;
            }

            _serverVehicles[serverVehicle.Id] = vehicle.Handle;
        }
        internal static void DeleteVehicle(Vehicle veh)
        {
            ServerVehicle sVeh;
            if ((sVeh = GetServerVehicleFromVehicle(veh)) != null)
            {
                _serverVehicles.Remove(sVeh.Id);
            }

            veh.Delete();
        }

        public static Vehicle GetVehicleFromHandle(NetHandle handle)
        {
            return NAPI.Pools.GetAllVehicles().Find(v => v.Handle == handle);
        }

        public static Vehicle GetVehicleFromId(int id)
        {
            return NAPI.Pools.GetAllVehicles().Find(v => v.Handle.Value == id);
        }

        public static Vehicle GetVehicleFromServerVehicle(ServerVehicle serverVehicle)
        {
            if (!_serverVehicles.ContainsKey(serverVehicle.Id))
            {
                return null;
            }

            return GetVehicleFromHandle(_serverVehicles[serverVehicle.Id]);
        }

        public static ServerVehicle GetServerVehicleFromVehicle(Vehicle veh, DatabaseContext dbContext = null)
        {
            dbContext = dbContext ?? new DatabaseContext();

            foreach (KeyValuePair<int, NetHandle> pair in _serverVehicles)
            {
                if (pair.Value == veh.Handle)
                {
                    return dbContext.ServerVehicles.Find(pair.Key);
                }
            }

            return null;
        }

        public static bool IsValidHash(uint hash)
        {
            foreach (VehicleHash vh in Enum.GetValues(typeof(VehicleHash)))
            {
                if ((uint)vh == hash) return true;
            }

            foreach (string mod in _enabledMods)
            {
                if (NAPI.Util.GetHashKey(mod) == hash) return true;
            }

            return false;
        }
    }
}
