using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Interfaces;
using Nancy;
using Nancy.Responses;
using Nancy.ViewEngines;

namespace RaceLapTimer.Modules
{
    public class HistoryModule : NancyModule
    {
        private IContainerHelper _helper;
        private readonly IExportManager _exporter;
        private readonly IDocumentPathProvider _docPathProvider;

        public HistoryModule(IContainerHelper helper
            , IExportManager exportManager
            , IDocumentPathProvider docPathProvider) : base("/history")
        {
            _helper = helper;
            _exporter = exportManager;
            _docPathProvider = docPathProvider;

            Get[""] = args => GetHistoryHomePage();
            //make this async
            Get["/pdf/{id}"] = (args) => GetPdfFile(args);
            Get["/details/{id}"] = args => GetExportPage(args);
        }

        private dynamic GetExportPage(dynamic args)
        {
            var rand = new Random();
            var model = new RaceSessionHistory
            {
                Title = "testmodel",
                RaceMode = RaceMode.COMPETITION,
                LapCount = 21
            };
            #region Pilots
            var pilot1 = new Pilot
            {
                Id = 1,
                ImageUrl = "/images/pilotPic.png",
                Name = "testExportPilotName",
                TeamName = "tstEx",
                TransponderToken = 66
            };
            var pilot2 = new Pilot
            {
                Id = 2,
                ImageUrl = "/images/pilotPic.png",
                Name = "testExportPilot2Name",
                TeamName = "tstEx2",
                TransponderToken = 68
            };
            var pilot3 = new Pilot
            {
                Id = 3,
                ImageUrl = "/images/pilotPic.png",
                Name = "testExportPilot3Name",
                TeamName = "tstEx2",
                TransponderToken = 65
            };
            var pilot4 = new Pilot
            {
                Id = 4,
                ImageUrl = "/images/pilotPic.png",
                Name = "testExportPilot4Name",
                TeamName = "tstEx4",
                TransponderToken = 14
            };
            var pilot5 = new Pilot
            {
                Id = 2,
                ImageUrl = "/images/pilotPic.png",
                Name = "testExportPilot5Name",
                TeamName = "tstEx",
                TransponderToken = 17
            };
            var pilot6 = new Pilot
            {
                Id = 2,
                ImageUrl = "/images/pilotPic.png",
                Name = "testExportPilot6Name",
                TeamName = "tstEx3",
                TransponderToken = 15
            };
            var pilot7 = new Pilot
            {
                Id = 2,
                ImageUrl = "/images/pilotPic.png",
                Name = "testExportPilot7Name",
                TeamName = "tstEx2",
                TransponderToken = 14
            }; 
            #endregion
            #region laps
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 1,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 2,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 3,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 4,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 5,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 6,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 7,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 8,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 9,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 10,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 11,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 12,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 13,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 14,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 15,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 16,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 17,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 18,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 19,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 20,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            model.LapTimes.Add(new RaceLap
            {
                LapNumber = 21,
                LapTimeMs = rand.Next(10000,80000),
                OverallPositon = 1,
                RacerDetails = pilot1
            });
            #endregion
            model.Racers.Add(pilot1);
            model.Racers.Add(pilot2);
            model.Racers.Add(pilot3);
            model.Racers.Add(pilot4);
            model.Racers.Add(pilot5);
            model.Racers.Add(pilot6);
            model.Racers.Add(pilot7);
            model.FastestPilot = pilot1;
            return View["HistoricRaceDetails.cshtml", model];
        }

        private dynamic GetPdfFile(dynamic args)
        {
            #region old
            //var raceSessionId = (int)args.Id;
            //ViewLocationContext viewLocationContext = new ViewLocationContext()
            //{
            //    Context = Context,
            //    ModuleName = base.GetType().Name,
            //    ModulePath = ModulePath
            //};
            //var rendered = ViewFactory.RenderView("HistoryIndex.cshtml", null, viewLocationContext);
            //var content = "";
            //using (var ms = new MemoryStream())
            //{
            //    rendered.Contents.Invoke(ms);
            //    ms.Seek(0, SeekOrigin.Begin);
            //    using (TextReader reader = new StreamReader(ms))
            //    {
            //        content = reader.ReadToEnd();
            //    }
            //};
            //var filePath = string.Empty; 
            #endregion
            
                int raceId = args.id;
                string exportType = Request.Query["exporttype"].Value;
                var baseUrl = "http://localhost:8800";
                var exportFileName = "RaceSessionExport" + raceId + ".pdf";
                var exportFilePath = Path.Combine(_docPathProvider.GetPath(), exportFileName);
                //TODO: replace testHTML with the actual exporthtml page!
                var wc = new WebClient();
                var html = wc.DownloadString(string.Format("{0}/history/details/{1}", baseUrl, raceId));
                //Debug.WriteLine(html);
                //TBD: check if export is available already
                if (!File.Exists(exportFilePath))
                {
                    //if not..create the export
                    Stream stream;
                    _exporter.Export(exportType, html, baseUrl, out stream);
                    //then save it to the export to the documents folder
                    using (stream)
                    using (var fs = new FileStream(exportFilePath, FileMode.Create))
                    {
                        stream.Seek(0, SeekOrigin.Begin);
                        stream.CopyTo(fs);
                        fs.Flush(true);
                    }
                }
                //return the file.
                var resp = new StreamResponse(() => new FileStream(exportFilePath, FileMode.Open), MimeTypes.GetMimeType(exportFileName));
                return resp.AsAttachment(exportFileName);
                //throw new NotImplementedException();
                //return Response.AsFile(filePath);
        }

        private dynamic GetHistoryHomePage()
        {
            dynamic model = new ExpandoObject();
            var eM = _helper.Get<IExportManager>();

            model.ExportTypes = eM.GetExporterDetails();//new List<ExportProviderDetails> {new ExportProviderDetails {Type="PDF"} };

            return View["HistoryIndex.cshtml", model];
        }
    }
}
