using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AutoMapper;
using ClosedXML.Excel;
using CsvHelper;
using CsvHelper.Configuration;
using CsvHelper.Excel;
using InventoryTraker.Web.Models;

namespace InventoryTraker.Web.Utilities
{
	public class MovementReportWriter
	{
		public class MovementReportExportItem
		{
			public string Name { get; set; }
			public string UnitsPerCaseContainerType { get; set; }
			public string BeginningQuantity { get; set; }
			public string AddedQuantity { get; set; }
			public string TotalAvailableQuantity { get; set; }
			public string DistributedQuantity { get; set; }
			public string AdjustmentQuantity { get; set; }
			public string EndingQuantity { get; set; }

			public class AutoMapperProfile : Profile
			{
				public AutoMapperProfile()
				{
					Func<int, int, string> formatCases =
					(cases, unitsPerCase) => $"{cases * unitsPerCase} ({cases} cs)";

					Func<int, int, string> hideEmptyCases =
						(cases, unitsPerCase) =>
							cases > 0
							? formatCases(cases, unitsPerCase)
							: "";

					Func<int, int, string> negative =
						(cases, unitsPerCase) =>
							cases > 0
							? "- " + hideEmptyCases(cases, unitsPerCase)
							: "";

					CreateMap<MovementReportItem, MovementReportExportItem>()
						.ForMember(d => d.Name, opt => opt.MapFrom(i => i.InventoryType.Name))
						.ForMember(d => d.UnitsPerCaseContainerType,
							opt => opt.MapFrom(i => i.InventoryType.UnitsPerCaseContainerType))
						.ForMember(d => d.BeginningQuantity,
							opt => opt.MapFrom(i =>
								formatCases(i.BeginningQuantity, i.InventoryType.UnitsPerCase)))
						.ForMember(d => d.AddedQuantity,
							opt => opt.MapFrom(i =>
								hideEmptyCases(i.AddedQuantity, i.InventoryType.UnitsPerCase)))
						.ForMember(d => d.TotalAvailableQuantity,
							opt => opt.MapFrom(i =>
								hideEmptyCases(i.TotalAvailableQuantity, i.InventoryType.UnitsPerCase)))
						.ForMember(d => d.AdjustmentQuantity,
							opt => opt.MapFrom(i =>
								negative(i.AdjustmentQuantity, i.InventoryType.UnitsPerCase)))
						.ForMember(d => d.DistributedQuantity,
							opt => opt.MapFrom(i =>
								hideEmptyCases(i.DistributedQuantity, i.InventoryType.UnitsPerCase)))
						.ForMember(d => d.EndingQuantity,
							opt => opt.MapFrom(i =>
								formatCases(i.EndingQuantity, i.InventoryType.UnitsPerCase)));
				}
			}
		}

		private sealed class MovementReportMap : CsvClassMap<MovementReportExportItem>
		{
			public MovementReportMap()
			{
				Map(m => m.Name).Name("Name of Commodity");
				Map(m => m.UnitsPerCaseContainerType).Name("Pack Size / Units per Case");
				Map(m => m.BeginningQuantity).Name("Beginning Inventory");
				Map(m => m.AddedQuantity).Name("Units Rec'd");
				Map(m => m.TotalAvailableQuantity).Name("Total Units Available");
				Map(m => m.AdjustmentQuantity).Name("Adjustments (show + or -)");
				Map(m => m.DistributedQuantity).Name("Units Distributed");
				Map(m => m.EndingQuantity).Name("Ending Inventory");
			}
		}

		private readonly IMapper _mapper;

		public MovementReportWriter(IMapper mapper)
		{
			_mapper = mapper;
		}

		public byte[] Write(MovementReport report)
		{
			using (var stream = new MemoryStream())
			{
				WriteStream(report, stream);
				return stream.ToArray();
			}
		}

		public void WriteStream(MovementReport report, Stream stream)
		{
			using (var workbook = new XLWorkbook(XLEventTracking.Disabled))
			{
				var worksheet = workbook.AddWorksheet("Monthly Inventory Report");
				using (var writer = new CsvWriter(new ExcelSerializer(worksheet)))
				{
					writer.Configuration.RegisterClassMap(new MovementReportMap());
					writer.WriteField("Monthly Inventory Report");
					writer.NextRecord();
					writer.WriteField<string>($"Month: {report.Month:MMMM yyyy}");
					writer.NextRecord();
					var items =
						_mapper.Map<IEnumerable<MovementReportItem>, IEnumerable<MovementReportExportItem>>
							(report.Items)
							.OrderBy(i => i.Name);
					writer.WriteRecords(items);
					workbook.SaveAs(stream);
				}
			}
		}
	}
}