using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using InventoryTraker.Web.Core;
using InventoryTraker.Web.Data;
using InventoryTraker.Web.Models;

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

		public InventoryController(AppDbContext context)
		{
			_context = context;
		}

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

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

			return BetterJson(viewModels);
		}

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

		private IQueryable<Inventory> AllInventory()
		{
			return _context
				.Inventories
				.Where(x => x.Quantity > 0)
				.OrderBy(x => x.InventoryType.Name);
		}

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

			var inventory = Mapper.Map<Inventory>(form);
			inventory.InventoryType = _context.InventoryTypes.Find(form.InventoryTypeId);

			if (inventory.InventoryType == null)
				return GetErrorListJson("Inventory Type not found");

			_context.Inventories.Add(inventory);
			inventory.Transactions = new List<Transaction>
			{
				new Transaction
				{
					TransactionType = TransactionType.Added,
					AddedQuantity = inventory.Quantity,
					CurrentQuantity = inventory.Quantity,
					Memo = "Arrival",
					Timestamp = DateTime.Now,
					TransactionDate = inventory.AddedDate
				}
			};
			_context.SaveChanges();

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

		public JsonResult Distribute(InventoryDistributeForm form)
		{
			if (!ModelState.IsValid)
				return GetModelStateErrorListJson();

			var errors = new List<string>();

			foreach (var quantityForm in form.InventoryQuantities)
			{
				var inventory = _context.Inventories.Find(quantityForm.InventoryId);
				
				// check if it's really there
				if (inventory == null)
				{
					errors.Add($"'{quantityForm.InventoryId}' not found");
					continue;
				}

				if (inventory.Quantity < quantityForm.Quantity)
					errors.Add(
						$"'{inventory.InventoryType.Name}' has only {inventory.Quantity} qty, " +
						$"cannot remove {quantityForm.Quantity}");

				inventory.Quantity -= quantityForm.Quantity;

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

				inventory.Transactions.Add(new Transaction
				{
					TransactionType = TransactionType.Distributed,
					RemovedQuantity = quantityForm.Quantity,
					CurrentQuantity = inventory.Quantity,
					Memo = 
						string.IsNullOrEmpty(form.Memo) 
							? $"{form.Memo} | "
							: "" 
						+ $"Distributed to {form.Destination}",
					Timestamp = DateTime.Now,
					TransactionDate = form.DistributedDate
				});
			}

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

			_context.SaveChanges();

			return BetterJson(AllInventory()
				.ProjectTo<InventoryViewModel>()
				.ToArray());
		}

		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.InventoryType.Name}' 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.InventoryType.Name}' 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));
		}
	}
}