using System;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using MileageTraker.Web.Attributes;
using MileageTraker.Web.DAL;
using MileageTraker.Web.Utility;
using MileageTraker.Web.ViewModels.FuelLog;
using ImportUploadViewModel = MileageTraker.Web.ViewModels.FuelLog.ImportUploadViewModel;

namespace MileageTraker.Web.Controllers
{
	[Authorize(Roles = "Administrator, Developer")]
	public class FuelLogController : ControllerBase
    {
		public ViewResult Index(FuelLogQueryViewModel query)
		{
			var validLogYearMonths = DataService.GetValidFuelLogMonths();

			if (!validLogYearMonths.Any()) // this means no logs in DB
				return View("Empty");

			// default parameter processing
			if (!query.HasParameters())
			{
				query.FiscalYear = validLogYearMonths.First().Year;
				query.Month = validLogYearMonths.First().Month;
			}

			var fuelLogs = DataService.GetFuelLogs();

			var flvm = from fl in DataService.FilterFuelLogs(fuelLogs, query).ToList()
						   orderby fl.Date ascending
					   select new FuelLogIndexViewModel(fl);

			var viewModel = new FuelLogResultsViewModel(flvm, query, CustomExtensions.YearMonthList(validLogYearMonths));

			return View(viewModel);
		}

		[ActionLog]
		public ActionResult Export(FuelLogQueryViewModel query)
		{
			var validLogYearMonths = DataService.GetValidFuelLogMonths();

			// default parameter processing
			if (!query.HasParameters())
			{
				query.FiscalYear = validLogYearMonths.First().Year;
				query.Month = validLogYearMonths.First().Month;
			}

			var fuelLogs = DataService.GetFuelLogs();
			var filteredLogs =
				from fl in DataService.FilterFuelLogs(fuelLogs, query).ToList()
				orderby fl.Date ascending
				select new FuelLogIndexViewModel(fl);

			var name = string.Format("FuelLogs_{0}", query);

			var export = ExcelWriter<FuelLogIndexViewModel>.WriteXls(filteredLogs, name, name);
			return File(export, "application/ms-excel", name + ".xls");
		}

		public ViewResult Details(int id)
		{
			var fuelLog = DataService.GetFuelLog(id);
			var vm = new FuelLogViewModel(fuelLog) { VehicleId = DataService.GetVehicleIdByTag(fuelLog.TagNumber) };
			return View(vm);
		}

		public ViewResult Match(int id)
		{
			var fuelLog = DataService.GetFuelLog(id);
			var fuelLogViewModel = new FuelLogViewModel(fuelLog) {VehicleId = DataService.GetVehicleIdByTag(fuelLog.TagNumber)};

			var logs = from l in DataService.GetPossibleMatchingLogs(fuelLog).ToList()
					   where l != fuelLog.Log
			           let v = DataService.GetVehicle(l.VehicleId)
					   let vm = new LogMatchViewModel(l, v, fuelLogViewModel)
					   orderby vm.MismatchCount ascending
					   select vm;
			
			var matchViewModel = 
				new MatchViewModel
					{
						FuelLog = fuelLogViewModel,
						MatchedLogs = logs.ToList()
					};

			if (fuelLog.Log != null)
				matchViewModel.CurrentlyMatchedLog = new LogMatchViewModel(fuelLog.Log, DataService.GetVehicle(fuelLog.Log.VehicleId), fuelLogViewModel);

			// When creating a new Log to match the fuel log, this holds the ID between actions
			TempData["FuelLogId"] = id;

			return View(matchViewModel);
		}

		[HttpPost]
		public ActionResult Match(int fuelLogId, int logId)
		{
			var fuelLog = DataService.GetFuelLog(fuelLogId);
			var log = DataService.GetLog(logId);
			fuelLog.Log = log;
			DataService.UpdateFuelLog(fuelLog);

			return RedirectToAction("Match", new {id = fuelLogId});
		}

		#region Import

		public ActionResult ImportUpload()
		{
			return View();
		}

		[HttpPost]
		[ActionLog]
		public ActionResult Import(ImportUploadViewModel viewModel)
		{
			if (ModelState.IsValid && viewModel.File != null && viewModel.File.ContentLength > 0)
			{
				var fileName = Path.GetFileName(viewModel.File.FileName);
				var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
				var fileInfo = new FileInfo(path);
				viewModel.File.SaveAs(path);

				try
				{
					var fuelLogs = FuelmanCsvImporter.Import(fileInfo);
					foreach (var fuelLog in fuelLogs)
						fuelLog.SourceFilename = fileName;
					
					// todo: delete file?

					var fls = (from fuelLog in fuelLogs
					               let prevAdds = DataService.GetDuplicateFuelLogs(fuelLog)
					               select new {ImportedFuelLog = fuelLog, PrevAdded = prevAdds.FirstOrDefault()}).ToList();

					// add new logs to the database
					DataService.AddFuelLogs(fls.Where(fl => fl.PrevAdded == null).Select(fl => fl.ImportedFuelLog));

					var vms = from fl in fls
					          let vm = fl.PrevAdded == null
						                ? new ImportFuelLogViewModel(fl.ImportedFuelLog)
						                : new ImportFuelLogViewModel(fl.PrevAdded) {PreviouslyAdded = true}
					          select vm;
					return View(vms.ToList());
				}
				catch (Exception ex)
				{
					TempData["StatusMessage"] = "Problem reading document: " + ex.Message;
					TempData["StatusMessage-Type"] = "alert-error";
				}
				finally
				{
					if (fileInfo.Exists) 
						fileInfo.Delete();
				}
			}
			return RedirectToAction("ImportUpload");
		}

		enum MatchStatus
		{
			Match,
			NoMatch,
			Error
		}

		[HttpPost]
		public ActionResult ImportMatch(int fuelLogId)
		{
			var fuelLog = DataService.GetFuelLog(fuelLogId);
			if (fuelLog == null)
			{
				return Json(new
				{
					Status = MatchStatus.Error.ToString(),
					Message = "Fuel Log not found with given ID: " + fuelLogId
				}, JsonRequestBehavior.AllowGet);
			}
			if (fuelLog.Log != null)
			{
				return Json(new
				{
					Status = MatchStatus.NoMatch.ToString(),
					Message = "Already matched to log",
					Action = RenderRazorViewToString("MatchLink", new MatchLinkViewModel(fuelLog))

				}, JsonRequestBehavior.AllowGet);
			}

			// run the match
			var matchingLog = DataService.GetMatchingLog(fuelLog);
			if (matchingLog == null)
			{
				return Json(new
				{
					Status = MatchStatus.NoMatch.ToString(),
					Message = "Unable to find match",
					Action = RenderRazorViewToString("MatchLink", new MatchLinkViewModel(fuelLog))
				}, JsonRequestBehavior.AllowGet);
			}
			fuelLog.Log = matchingLog;
			DataService.UpdateFuelLog(fuelLog);
			return Json(new
			{
				Status = MatchStatus.Match.ToString(),
				Action = RenderRazorViewToString("MatchLink", new MatchLinkViewModel(fuelLog))
			}, JsonRequestBehavior.AllowGet);
		}

		#endregion
	}
}
