using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using GreenTree.Strohrmann.ERP.Core.Domain.Business;
using GreenTree.Strohrmann.ERP.Core.Extension;
using GreenTree.Strohrmann.ERP.Core.Helper;
using GreenTree.Strohrmann.ERP.Domain.Extension;
using GreenTree.Strohrmann.ERP.Domain.Model;
using GreenTree.Strohrmann.ERP.Services.Geolocator;
using GreenTree.Strohrmann.ERP.Web.Extension;
using GreenTree.Strohrmann.ERP.Web.Models.Business;
using GreenTree.Strohrmann.ERP.Web.Models.Rights.User;
using GreenTree.Strohrmann.ERP.Web.Validators;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace GreenTree.Strohrmann.ERP.Web.Controllers
{
    public class CraftController : Controller
    {
        #region DI fields

        // The global DbContext
        private readonly ERPDbContext _eRPDbContext;

        #endregion

        #region Ctor

        /// <summary>
        /// Initializes a new instance of the CraftController class
        /// </summary>
        /// <param name="eRPDbContext">Global DbContext.</param>
        public CraftController(ERPDbContext eRPDbContext)
        {
            _eRPDbContext = eRPDbContext;
        }

        #endregion

        #region Actions

        // GET: CraftController
        public ActionResult Index()
        {
            var crafts = _eRPDbContext.Crafts
                .ToList()
                .Select(c => new CraftModel(c));

            return View(crafts);
        }

        // GET: CraftController/Details/5
        public ActionResult Details(int id)
        {
            var craft = _eRPDbContext.Crafts
                .FirstOrDefault(c => c.Id == id);

            var craftModel = new CraftModel(craft);

            return View(craftModel);
        }

        // GET: CraftController/Create
        public ActionResult Create()
        {
            AddEmployeeListForSelection();
            AddMaterialListForSelection();

            return View();
        }

        // POST: CraftController/Create
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(CraftModel model)
        {
            if (!ModelState.IsValid)
            {
                AddEmployeeListForSelection();
                AddMaterialListForSelection();

                foreach (var item in model.CraftMaterials)
                {
                    if (item.Value.Amount % 1 != 0)
                        item.Value.Amount /= 10;

                    item.Value.CalculationFactor = item.Value.CalculationFactor / 100;
                }

                return View(model);
            }

            var craft = new Craft
            {
                Name = model.Name,
                CreationDate = model.CreationDate,
                Customer = _eRPDbContext.Customers.Find(model.CustomerId),
                Comment = model.Comment,
                CreatedBy = User.Identity.Name,
                CreatedOn = DateTime.Now
            };

            craft.CraftEmployees = new List<CraftEmployee>(
                model.CraftEmployees
                    .Select(ce => new CraftEmployee
                    {
                        Craft = craft,
                        Employee = _eRPDbContext.Employees.Find(ce.Value.EmployeeId),
                        Amount = ce.Value.Amount,
                        Value = Convert.ToDecimal(ce.Value.Value),
                        Comment = ce.Value.Comment
                    }));

            craft.CraftMaterials = new List<CraftMaterial>(
                model.CraftMaterials
                    .GroupBy(cm => cm.Value.MaterialId)
                    .Select(cm => new CraftMaterial
                    {
                        Craft = craft,
                        Material = _eRPDbContext.Materials.Find(cm.Key),
                        Amount = cm.Sum(v => v.Value.Amount),
                        CalculationFactor = cm.Average(v => v.Value.CalculationFactor / 100),
                        Value = cm.Sum(v => Convert.ToDecimal(v.Value.Value))
                    }));

            _eRPDbContext.Crafts.Add(craft);
            _eRPDbContext.SaveChanges();

            return RedirectToAction(nameof(Index));
        }

        // GET: CraftController/Edit/5
        public ActionResult Edit(int id)
        {
            AddEmployeeListForSelection();
            AddMaterialListForSelection();

            var craft = _eRPDbContext.Crafts
                .FirstOrDefault(c => c.Id == id);

            var craftModel = new CraftModel(craft);

            return View(craftModel);
        }

        // POST: CraftController/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(int id, CraftModel model)
        {
            if (!ModelState.IsValid)
            {
                AddEmployeeListForSelection();
                AddMaterialListForSelection();

                foreach (var item in model.CraftMaterials)
                {
                    if (item.Value.Amount % 1 != 0)
                        item.Value.Amount /= 10;

                    item.Value.CalculationFactor = item.Value.CalculationFactor / 100;
                }

                return View(model);
            }

            var craft = _eRPDbContext.Crafts
                .FirstOrDefault(u => u.Id == id);

            craft.Name = model.Name;
            craft.CreationDate = model.CreationDate;
            craft.Customer = _eRPDbContext.Customers.Find(model.CustomerId);
            craft.Comment = model.Comment;
            craft.ChangedBy = User.Identity.Name;
            craft.ChangedOn = DateTime.Now;
            craft.CraftEmployees.Clear();
            craft.CraftMaterials.Clear();
            craft.CraftEmployees = new List<CraftEmployee>(
                model.CraftEmployees
                    .Select(ce => new CraftEmployee
                    {
                        Craft = craft,
                        Employee = _eRPDbContext.Employees.Find(ce.Value.EmployeeId),
                        Amount = ce.Value.Amount,
                        Value = Convert.ToDecimal(ce.Value.Value),
                        Comment = ce.Value.Comment
                    }));

            craft.CraftMaterials = new List<CraftMaterial>(
                model.CraftMaterials
                    .GroupBy(cm => cm.Value.MaterialId)
                    .Select(cm => new CraftMaterial
                    {
                        Craft = craft,
                        Material = _eRPDbContext.Materials.Find(cm.Key),
                        Amount = cm.Sum(v => v.Value.Amount),
                        CalculationFactor = cm.Average(v => v.Value.CalculationFactor / 100),
                        Value = cm.Sum(v => Convert.ToDecimal(v.Value.Value))
                    }));

            _eRPDbContext.SaveChanges();

            return RedirectToAction(nameof(Index));
        }

        // POST: CraftController/Delete/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Delete(int id, IFormCollection collection)
        {
            var craft = _eRPDbContext.Crafts
                .FirstOrDefault(c => c.Id == id);

            _eRPDbContext.Crafts.Remove(craft);
            _eRPDbContext.SaveChanges();

            return RedirectToAction(nameof(Index));
        }

        #endregion

        #region Partials

        // GET: CraftController/AddCraftEmployeePartial
        public ActionResult AddCraftEmployeePartial(CraftEmployeeModel craftEmployeeModel)
        {
            AddEmployeeListForSelection();

            ModelState.Clear();

            return PartialView("~/Views/Craft/_CraftEmployeePartial.cshtml", craftEmployeeModel);
        }

        // GET: CraftController/AddCraftMaterialPartial
        public ActionResult AddCraftMaterialPartial(CraftMaterialModel craftMaterialModel)
        {
            AddMaterialListForSelection();

            craftMaterialModel.CalculationFactor = 1.2m;

            return PartialView("~/Views/Craft/_CraftMaterialPartial.cshtml", craftMaterialModel);
        }

        #endregion

        #region Values

        // POST: CraftController/CalculateEmployeeValue
        [HttpPost]
        public ActionResult CalculateEmployeeValue(CraftEmployeeModel craftEmployeeModel)
        {
            if (craftEmployeeModel == null)
                return Ok(0);

            if (craftEmployeeModel.EmployeeId == default)
                return Ok(0);

            var employee = _eRPDbContext.Employees.Find(craftEmployeeModel.EmployeeId);
            var result = employee.EmployeeDegree.Value * craftEmployeeModel.Amount;

            return Ok(result);
        }

        // POST: CraftController/CalculateMaterialValue
        [HttpPost]
        public ActionResult CalculateMaterialValue(CraftMaterialModel craftMaterialModel)
        {
            if (craftMaterialModel == null)
                return Ok(0);

            if (craftMaterialModel.MaterialId == default)
                return Ok(0);

            var material = _eRPDbContext.Materials.Find(craftMaterialModel.MaterialId);
            var result = material.NetValue * craftMaterialModel.Amount * (craftMaterialModel.CalculationFactor / 100);

            return Ok(result);
        }

        // POST: CraftController/CalculateMaterialCalculationFactor
        [HttpPost]
        public ActionResult CalculateMaterialCalculationFactor(CraftMaterialModel craftMaterialModel)
        {
            if (craftMaterialModel == null)
                return Ok(0);

            if (craftMaterialModel.MaterialId == default)
                return Ok(0);

            var material = _eRPDbContext.Materials.Find(craftMaterialModel.MaterialId);
            var result = Convert.ToDecimal(craftMaterialModel.Value) / (material.NetValue * craftMaterialModel.Amount) * 100;

            return Ok(result);
        }

        #endregion

        #region Helper

        /// <summary>
        /// Adds the employee SelectListItem collection to the current ViewData dictionary
        /// </summary>
        private void AddEmployeeListForSelection()
        {
            ViewData.AddSelectList("AvailableEmployees",
                _eRPDbContext.Employees
                    .ToList()
                    .Select(e => new EmployeeModel(e)),
                e => e.Id, e => String.Format("{0} {1} ({2} - {3:n0}€ / Std.)",
                    e.Firstname, e.Lastname, e.EmployeeDegree.Name, e.EmployeeDegree.Value));
        }

        /// <summary>
        /// Adds the material SelectListItem collection to the current ViewData dictionary
        /// </summary>
        private void AddMaterialListForSelection()
        {
            ViewData.AddSelectList("AvailableMaterials",
                _eRPDbContext.Materials,
                m => m.Id, e => String.Format("{0} ({1})", e.Name, e.ItemNumber));
        }

        #endregion
    }
}
