using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using InventoryTraker.Web.Attributes;
using InventoryTraker.Web.Core;
using InventoryTraker.Web.Data;
using InventoryTraker.Web.Models;
using InventoryTraker.Web.Services;
using InventoryTraker.Web.Utilities;

namespace InventoryTraker.Web.Controllers
{
	public class InventoryController : ControllerBase
	{
		private readonly AppDbContext _context;
		private readonly IMapper _mapper;
		private readonly InventoryImporter _inventoryImporter;

		public InventoryController(AppDbContext context, IMapper mapper, InventoryImporter inventoryImporter)
		{
			_context = context;
			_mapper = mapper;
			_inventoryImporter = inventoryImporter;
		}

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

		public JsonResult All()
		{
			var viewModels =
				CurrentInventory()
				.ProjectTo<InventoryViewModel>(_mapper.ConfigurationProvider)
				.ToArray();

			return BetterJson(viewModels);
		}

		public JsonResult Find(string id)
		{
			var inventory = _context.Inventories.Find(id);
			var viewModel = _mapper.Map<InventoryViewModel>(inventory);
			return BetterJson(viewModel);
		}

		private IQueryable<Inventory> CurrentInventory()
		{
			return _context
				.Inventories
				.Where(i => i.Quantity > 0)
				.OrderByDescending(x => x.ShredReadyDate);
		}

		public ActionResult Export()
		{
			var writer = new InventoryReportWriter();

			var viewModels =
				CurrentInventory()
				.ProjectTo<InventoryViewModel>(_mapper.ConfigurationProvider)
				.ToArray();

			var excel = writer.Write(viewModels);

			var filename = $"Inventory{DateTime.Today:yyyyMMdd}.xlsx";

			return
				new FileContentResult(excel, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
				{
					FileDownloadName = filename
				};
		}

		[ActionLog]
		public JsonResult Add(InventoryAddForm form)
		{
			if (!ModelState.IsValid)
				return GetModelStateErrorListJson();

			var inventory = _mapper.Map<Inventory>(form);

			_context.Inventories.Add(inventory);
			inventory.Transactions = ModelHelper.GetAddedTransaction(inventory.AddedDate);
			_context.SaveChanges();

			var model = _mapper.Map<InventoryViewModel>(inventory);
			return BetterJson(model);
		}

		[ActionLog]
		public JsonResult Update(InventoryAddForm form)
		{
			if (!ModelState.IsValid)
				return GetModelStateErrorListJson();

			var inventory = _context.Inventories.Find(form.Id);
			_mapper.Map(form, inventory);

			_context.SaveChanges();

			var model = _mapper.Map<InventoryViewModel>(inventory);
			return BetterJson(model);
		}

		[ActionLog]
		public JsonResult Remove(InventoryRemoveForm form)
		{
			if (!ModelState.IsValid)
				return GetModelStateErrorListJson();

			var errors = new List<string>();

			var inventory = _context.Inventories.Find(form.InventoryId);
				
			// check if it's really there
			if (inventory == null)
			{
				errors.Add($"'{form.InventoryId}' not found");
			}
			else
			{
				if (inventory.Quantity < form.Quantity)
					errors.Add(
						$"'{inventory.Id}' has only {inventory.Quantity} qty, " +
						$"cannot remove {form.Quantity}");

				inventory.Quantity -= form.Quantity;

				var mostRecentTransaction =
					inventory.Transactions.OrderByDescending(t => t.TransactionDate).First();
				if (form.RemovedDate < mostRecentTransaction.TransactionDate)
					errors.Add($"'{inventory.Id}' most recent transaction " +
					           $"is {mostRecentTransaction.TransactionDate.ToShortDateString()}. " +
					           $"Cannot add a transaction on {form.RemovedDate.ToShortDateString()}.");

				inventory.Transactions.Add(new Transaction
				{
					TransactionType = form.TransactionType,
					RemovedQuantity = form.Quantity,
					CurrentQuantity = inventory.Quantity,
					Memo = form.Memo,
					Timestamp = DateTime.Now,
					TransactionDate = form.RemovedDate
				});
			}

			if (errors.Any())
				return GetErrorListJson(errors.ToArray());

			_context.SaveChanges();

			return BetterJson(_mapper.Map<InventoryViewModel>(inventory));
		}

	}
}