using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
using UniversityContracts.BindingModels;
using UniversityContracts.BusinessLogicContracts;
using UniversityContracts.ViewModels;
using UniversityEmployeeApp.Filters;
using UniversityEmployeeApp.Models;

namespace UniversityEmployeeApp.Controllers
{
    [AuthorizationFilter]

    public class HomeController : Controller
    {
            
        private readonly ILogger<HomeController> _logger;
        private readonly IEmployeeLogic _employeeLogic;
        private readonly IOperationLogic _carLogic;
        private readonly ICostLogic _costLogic;
        private readonly IPurchaseLogic _purchaseLogic;
        private readonly IPaymentLogic _paymentLogic;
        private readonly IReportLogic _reportLogic;

        private EmployeeViewModel? _employee;

        public HomeController(ILogger<HomeController> logger,
            IEmployeeLogic employeeLogic, IOperationLogic carLogic, ICostLogic costLogic,
            IPurchaseLogic purchaseLogic, IPaymentLogic paymentLogic, IReportLogic reportLogic)
        {
            _reportLogic = reportLogic;
            _paymentLogic = paymentLogic;
            _purchaseLogic = purchaseLogic;
            _costLogic = costLogic;
            _carLogic = carLogic;
            _employeeLogic = employeeLogic;
            _logger = logger;
        }

        private EmployeeViewModel Employee
        {
            get
            {
                if (_employee == null)
                {
                    try
                    {
                        _employee = _employeeLogic.ReadElement(new()
                        {
                            PhoneNumber = HttpContext.Session.GetString(SessionKeys.EmployeePhone),
                            Password = HttpContext.Session.GetString(SessionKeys.EmployeePassword),
                        });
                    }
                    catch (Exception e)
                    {
                        _logger.LogError(e, "Не удалось получить пользователя, хотя был пройден фильтр авторизации");
                        throw;
                    }
                }
                return _employee;
            }
        }

        public IActionResult Index()
        {
            return View();
        }
        public IActionResult Privacy()
        {
            return View(Employee);
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }

        public IActionResult Operations()
        {
            return View(_carLogic.ReadList(new() { EmployeeId = Employee.Id }));
        }

        public IActionResult Purchases()
        {
            return View(_carLogic.ReadList(new() { EmployeeId = Employee.Id }));
        }

        public IActionResult Costs()
        {
            return View(_costLogic.ReadList(new() { EmployeeId = Employee.Id }));
        }

        public IActionResult ReportFromOperations(string? getReport, string? sendToMail, DateTime startDate, DateTime endDate)
        {
            _logger.LogInformation("Попытка получить отчет: {@getReport}; {@sendToMail} Период: {0}---{1}", getReport, sendToMail, startDate, endDate);
            if (startDate > endDate)
            {
                throw new Exception("Дата начала больше даты конца периода");
            }
            if (getReport != null)
            {
                return View(_paymentLogic.ReadList(new()
                {
                    DateFrom = DateOnly.FromDateTime(startDate),
                    DateTo = DateOnly.FromDateTime(endDate)
                }));
            }
            if (sendToMail != null)
            {
                _reportLogic.SendPaymentsToEmail(
                    option: new()
                    {
                        DateFrom = DateOnly.FromDateTime(startDate),
                        DateTo = DateOnly.FromDateTime(endDate)
                    },
                    email: Employee.Email
                );
            }
            return View();
        }

        [HttpGet]
        public IActionResult Operation(int? id)
        {
            if (id.HasValue)
            {
                return View(_carLogic.ReadElement(new() { Id = id }));
            }
            return View();
        }

        [HttpPost]
        public void Operation(OperationBindingModel car)
        {
            var isOperationUpdate = Request.RouteValues.TryGetValue("id", out var identValue);
            isOperationUpdate &= int.TryParse((string?)identValue, out var id);

            _logger.LogInformation("При изменении обследования были получены данные: {_mark}; {_model}; {idUpdated}", car.Mark, car.Model, identValue);

            if (isOperationUpdate)
            {
                car.Id = id;
                _carLogic.Update(car);
                Response.Redirect("../Operations");
            }
            else
            {
                car.EmployeeId = Employee.Id;
                _carLogic.Create(car);
                Response.Redirect("Operations");
            }
        }

        public IActionResult RemoveOperation(int id)
        {
            _carLogic.Delete(new() { Id = id });
            return Redirect("~/Home/Operations");
        }

        [HttpGet]
        public FileResult ReportPurchasesInWord(int[] ids)
        {
            _logger.LogInformation("Запрошен отчет в формате word");
            _logger.LogInformation("Получено {count} обследований для отчета", ids.Length);

            MemoryStream mstream = new();
            _reportLogic.SavePurchasesToWord(new()
            {
                Ids = ids,
                Stream = mstream,
            });
            return File(mstream.ToArray(), System.Net.Mime.MediaTypeNames.Application.Octet, "reportWord.docx");
        }

        [HttpGet]
        public FileResult ReportPurchasesInExcel(int[] ids)
        {
            _logger.LogInformation("Запрошен отчет в формате excel");
            _logger.LogInformation("Получено {count} обследований для отчета", ids.Length);

            MemoryStream mstream = new();
            _reportLogic.SavePurchasesToExcel(new()
            {
                Ids = ids,
                Stream = mstream
            });
            return File(mstream.ToArray(), System.Net.Mime.MediaTypeNames.Application.Octet, "reportExcel.xlsx");
        }


        public IActionResult Cost(int? id)
        {
            if (id.HasValue)
            {
                return View(_costLogic.ReadElement(new() { Id = id }));
            }
            return View();
        }

        [HttpPost]
        public void Cost(string name, double price)
        {
            var isOperationUpdate = Request.RouteValues.TryGetValue("id", out var identValue);
            isOperationUpdate &= int.TryParse((string?)identValue, out var id);

            _logger.LogInformation("При изменении затрат были получены данные: {name}; {price}; {idUpdated}", name, price, identValue);
            CostBindingModel model = new()
            {
                NameOfCost = name,
                Price = price,
            };
            if (isOperationUpdate)
            {
                model.Id = id;
                _costLogic.Update(model);
                Response.Redirect("../Costs");
            }
            else
            {
                model.EmployeeId = Employee.Id;
                _costLogic.Create(model);
                Response.Redirect("Costs");
            }
        }

        public IActionResult RemoveCost(int id)
        {
            _costLogic.Delete(new() { Id = id });
            return Redirect("~/Home/Costs");
        }

        public IActionResult BindPurchase(int id)
        {
            ViewBag.Costs = _costLogic.ReadList(new() { EmployeeId = Employee.Id });
            ViewBag.SelectedId = id;
            ViewBag.Purchases = _purchaseLogic.ReadList();
            return View();
        }

        [HttpPost]
        public void BindPurchase(int cost, int purchase, int count)
        {
            var purchaseModel = _purchaseLogic.ReadElement(new() { Id = purchase });
            var costmodel = _costLogic.ReadElement(new() { Id = cost });
            _costLogic.Update(new()
            {
                Id = cost,
                Price = costmodel.Price,
                NameOfCost = costmodel.NameOfCost,
                PurchasesModels =
                {
                    [purchase] = new() { Count = count, PurchaseId = purchase }
                }
            });
            Response.Redirect("/Home/Costs");
        }

        public double CalcCostSum(int cost, int count)
        {
            return _costLogic.ReadElement(new() { Id = cost }).Price * count;
        }

    }
}