using System;
using System.Collections.Generic;
using System.Linq;
using Interfaces;

namespace RaceLapTimer
{
    public class TestProvider : IDbProvider
    {
        private readonly List<Pilot> _pilots;
        private readonly List<RaceSession> _sessions;
        private readonly List<SatelliteLog> _transponderLogs;

        public TestProvider()
        {
            #region Pilots
            _pilots = new List<Pilot>
            {
                new Pilot
                {
                    Id=1,
                    Name = "Pilot1",
                    TeamName = "PilotTeam 1",
                    ThingyName = "Kart1",
                    TransponderToken = 222,
                    ImageUrl = "/images/pilotPic.png"
                },
                new Pilot
                {
                    Id=2,
                    Name = "Pilot 2",
                    TeamName = "Pilot Team 2",
                    ThingyName = "Kart2",
                    TransponderToken = 200
                }
            };
            #endregion
            #region RaceSessions
            _sessions = new List<RaceSession>
            {
                #region Session 1
                new RaceSession
                {
                    Active = true,
                    CreatedAt = DateTime.UtcNow,
                    HotSeatEnabled = false,
                    Id = 1,
                    IdleTimeSeconds = 400,
                    Mode = RaceMode.STANDARD,
                    MaxLaps = 20,
                    SatelliteCount = 1,
                    TimePenaltyPerSatellite = 100,
                    Title = "TEST Session 1"
                }, 
                #endregion
                #region Session 2
                new RaceSession
                {
                    Active = false,
                    CreatedAt = DateTime.UtcNow,
                    HotSeatEnabled = false,
                    Id = 2,
                    IdleTimeSeconds = 400,
                    Mode = RaceMode.STANDARD,
                    MaxLaps = 10,
                    SatelliteCount = 1,
                    TimePenaltyPerSatellite = 100,
                    Title = "TEST Session 2"
                },
                #endregion
                #region Session 3
                new RaceSession
                {
                    Active = false,
                    CreatedAt = DateTime.UtcNow,
                    HotSeatEnabled = false,
                    Id = 3,
                    IdleTimeSeconds = 400,
                    Mode = RaceMode.STANDARD,
                    MaxLaps = 10,
                    SatelliteCount = 1,
                    TimePenaltyPerSatellite = 100,
                    Title = "TEST Session 3"
                },
                #endregion
                #region Session 4
                new RaceSession
                {
                    Active = false,
                    CreatedAt = DateTime.UtcNow,
                    HotSeatEnabled = false,
                    Id = 4,
                    IdleTimeSeconds = 400,
                    Mode = RaceMode.STANDARD,
                    MaxLaps = 10,
                    SatelliteCount = 1,
                    TimePenaltyPerSatellite = 100,
                    Title = "TEST Session 4"
                },
                #endregion
                #region Session 5
                new RaceSession
                {
                    Active = false,
                    CreatedAt = DateTime.UtcNow,
                    HotSeatEnabled = false,
                    Id = 4,
                    IdleTimeSeconds = 400,
                    Mode = RaceMode.STANDARD,
                    MaxLaps = 10,
                    SatelliteCount = 1,
                    TimePenaltyPerSatellite = 100,
                    Title = "TEST Session 4"
                }
            #endregion
            };
            #endregion
            _transponderLogs = new List<SatelliteLog>();
        }

        public List<RaceSession> GetRaceSessions(bool getActive)
        {
            return getActive ? _sessions.Where(x => x.Active == getActive).ToList() : _sessions;
        }

        public RaceSession GetRaceSession(int id)
        {
            return _sessions.FirstOrDefault(x => x.Id == id);
        }

        public bool CreateRaceSession(RaceSession session)
        {
            _sessions.Add(session);
            return true;
        }

        public bool StopRaceSession(RaceSession session)
        {
            var selectedSession = _sessions.FirstOrDefault(x => x.CreatedAt == session.CreatedAt 
                                                                && x.Title == session.Title 
                                                                && x.MaxLaps == session.MaxLaps 
                                                                && x.Mode == session.Mode
                                                                && x.IdleTimeSeconds == session.IdleTimeSeconds);
            if (selectedSession == null)
            {
                return false;
            }
            selectedSession.Active = false;
            selectedSession.UpdatedAt = DateTime.UtcNow;
            return true;
        }

        public bool DeleteRaceSession(int sessionId)
        {
            if (_sessions.All(x => x.Id != sessionId))
            {
                return false;
            }
            var session = _sessions.Find(x => x.Id == sessionId);
            return _sessions.Remove(session);
        }

        public List<Pilot> GetPilotsList()
        {
            return _pilots;
        }

        public Pilot GetPilot(int pilotId)
        {
            return _pilots.FirstOrDefault(x => x.Id == pilotId);
        }

        public bool CreatePilot(Pilot pilot)
        {
            if (_pilots.Any(x => x.TransponderToken == pilot.TransponderToken))
                return false;
            pilot.Id= _pilots.Max(x => x.Id) + 1;
            _pilots.Add(pilot);
            return true;
        }

        public bool UpdatePilot(Pilot pilot)
        {
            if (_pilots.All(x => x.Id != pilot.Id))
            {
                return false;
            }
            var p = _pilots.First(x => x.Id == pilot.Id);
            p.ImageUrl = pilot.ImageUrl;
            p.TransponderToken = pilot.TransponderToken;
            p.Name = pilot.Name;
            p.TeamName = pilot.TeamName;
            p.ThingyName = pilot.ThingyName;
            return true;
        }

        public bool DeletePilot(int id)
        {
            return _pilots.Remove(_pilots.FirstOrDefault(x => x.Id == id));
        }

        public bool RemoveTransponderAssociation(int pilotId)
        {
            if (_pilots.All(x => x.Id != pilotId))
                return false;
            var pilot = _pilots.First(x => x.Id == pilotId);
            pilot.TransponderToken = -1;
            return true;
        }

        public int GetLastScannedId()
        {
            var rand = new Random();
            return rand.Next(0, 100);
        }

        public void StoreTransponderLog(SatelliteLog log)
        {
            var sessionId = GetCurrentRaceSessionId();
            var session = GetRaceSession(sessionId);
            log.RaceSessionId = sessionId;
            //Store the log..
            _transponderLogs.Add(log);
            // check fastest pilot!
            var fastestLapTime = GetFastestLapTimeMs(sessionId);
            var user = GetUserByTransponder(fastestLapTime.TransponderToken);
            session.FastestLap = fastestLapTime.LapTimeMs;
            session.FastestPilotId = user.Id;
            session.FastestPilotName = user.Name;
        }

        private SatelliteLog GetFastestLapTimeMs(int sessionId)
        {
            var sessionLogs = _transponderLogs.Where(x => x.RaceSessionId == sessionId);
            sessionLogs = sessionLogs.OrderByDescending(x => x.LapTimeMs);
            var fastestLog = sessionLogs.First();
            return fastestLog;
        }

        private int GetCurrentRaceSessionId()
        {
            var activeSessions = _sessions.Where(x => x.Active).ToList();
            if (activeSessions.Any() || activeSessions.Count > 1)
                return -1;  //either dont have any, or have more than 1!!!
            var session = activeSessions.First();
            return session.Id;
        }

        private Pilot GetUserByTransponder(int token)
        {
            return _pilots.FirstOrDefault(x => x.TransponderToken == token);
        }
    }
}