using ElectronicsShopContracts.BindingModels;
using ElectronicsShopContracts.BusinessLogicContracts;
using ElectronicsShopContracts.SearchModels;
using ElectronicsShopContracts.ViewModels;
using ElectronicsShopDataBaseImplement;
using ElectronicsShopDataBaseImplement.Models;
using ElectronicsShopDataModels.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;

namespace ElectronicsShopRestAPI.Controllers {

	[Route("api/[controller]/[action]")]
	[ApiController]
    public class MainController : Controller {

        private readonly ILogger _logger;
        private readonly IProductLogic _product;
        private readonly IOrderLogic _order;
        private readonly IPaymeantLogic _paymeant;
        private readonly IReportClientLogic _reportClientLogic;

        private Dictionary<int, (IProductModel, int)> _productlist;

        public MainController(ILogger<MainController> logger, IProductLogic product, 
                            IOrderLogic orderLogic, IPaymeantLogic paymeant, IReportClientLogic reportClientLogic) {
            _logger = logger;
            _product = product;
            _order = orderLogic;
            _productlist = new Dictionary<int, (IProductModel, int)>();
            _paymeant = paymeant;
            _reportClientLogic = reportClientLogic;
        }

		[HttpGet]
		public List<ProductViewModel>? GetProducts(int? _costitemid) {
			try {
                if (_costitemid != null) {
                    return _product.ReadList(new ProductSearchModel { CostItemID = _costitemid });
                }
				return _product.ReadList(null);
			}
			catch (Exception ex) {
				_logger.LogError(ex, $"Ошибка получения данных");
				throw;
			}
		}

        [HttpGet]
        public ProductViewModel? GetProduct(int? _productID, int? _costitemID)
        {
            try
            {
                if (_costitemID != null) {
                    return _product.ReadElement(new ProductSearchModel { CostItemID = _costitemID });
                }
                return _product.ReadElement(new ProductSearchModel
                {
                    ID = _productID
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Ошибка получения товаров id={Id}", _productID);
                throw;
            }
        }
        [HttpGet]
        public List<OrderViewModel>? GetOrders(int _clientID) {
            try
            {
                return _order.ReadList(new OrderSearchModel
                {
                    ClientID = _clientID
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Ошибка получения списка заказов клиента id = {Id} ", _clientID);
                throw;
            }
        }

        [HttpGet]
        public OrderViewModel? GetOrder(int? _clientID, int? _orderID) { 
            try {
				if (_orderID.HasValue) {
					return _order.ReadElement(new OrderSearchModel { ID = _orderID });
				}
				return _order.ReadElement(new OrderSearchModel { ClientID = _clientID });
            }
            catch (Exception ex) {
                _logger.LogError(ex, $"Ошибка получения данных clientid = {_clientID}");
                throw;
            }
        }

        [HttpPost]
        public void DeleteOrders(OrderBindingModel model) {
            try {
                _order.Delete(model);
            }
            catch (Exception ex) {
                _logger.LogError(ex, "Ошибка удаления заказа");
                throw;
            }
        }

        [HttpPost]
        public void CreateOrder(OrderBindingModel model) {
            try {
                _order.CreateOrder(model);
            }
            catch (Exception ex) {
                _logger.LogError(ex, "Ошибка создания заказа");
                throw;
            }
        }

        [HttpGet]
        public List<List<string>> GetOrderProducts(int _orderid) {
			var list = new List<List<string>>();
			try {
                var products = _order.ReadElement(new OrderSearchModel { ID = _orderid});
                
                if (products == null) {
                    return list; 
                }

                foreach (var pr in products.ProductList) {
					var sentence = new List<string> {
						JsonConvert.SerializeObject(pr.Value.Item1),
						JsonConvert.SerializeObject(pr.Value.Item2.ToString())
					};

                    list.Add(sentence);
                }
                return list;
            }
            catch (Exception ex) {
                _logger.LogError(ex, "Ошибка получения списка товаров");
                throw;
            }
		}

        [HttpPost]
        public void AddProduct(List<string> jslist) {
            var product = JsonConvert.DeserializeObject<ProductViewModel>(jslist[0]) ?? throw new Exception("Ошибка десериализации");
            int count = JsonConvert.DeserializeObject<int>(jslist[1]);
            int orderid = JsonConvert.DeserializeObject<int>(jslist[2]);

            var view = _order.ReadElement(new OrderSearchModel { ID = orderid });

            if (view != null) {
                _productlist = view.ProductList;
            }
            else {
                throw new Exception("Такого заказа нет");
            }

            _logger.LogInformation($"Добавление нового товара: {product.ProductName} - {count}");
            if (_productlist.ContainsKey(product.ID)) {
                _productlist[product.ID] = (product, count);
            }
            else {
                _productlist.Add(product.ID, (product, count));
            }

            if (_productlist == null || _productlist.Count == 0) {
                _logger.LogInformation("Корзина пуста, ошибка");
            }
            _logger.LogInformation("Сохранение Заказа");

            try {
                var model = new OrderBindingModel {
                    ID = orderid,
                    ClientID = view.ClientID,
                    DateCreate = view.DateCreate,
                    ProductList = _productlist ?? new Dictionary<int, (IProductModel, int)>(),
                    Sum = Calc(_productlist ?? new Dictionary<int, (IProductModel, int)>()),
                    Status = view.Status,
                };
                var operationResult = _order.Update(model);
                if (!operationResult) {
                    throw new Exception("Ошибка при сохранении, дополнительная информация в логах");
                }
            }
            catch (Exception ex) {
                _logger.LogError(ex, "Ошибка добавления товара");
                throw;
            }
		}

        [HttpPost]
        public void DeleteProductOrder(List<string> jslist) {

            int _orderId = JsonConvert.DeserializeObject<int>(jslist[0]);
			int _productId = JsonConvert.DeserializeObject<int>(jslist[1]);

            var view = _order.ReadElement(new OrderSearchModel { ID = _orderId });
            if (view == null) {
				_logger.LogError("Ошибка получения данных");
                return;
            }

            _productlist = view.ProductList;
            foreach (var item in _productlist) {
                if (item.Key == _productId) {
					_productlist.Remove(_productId);
                }
            }

            try {
                var model = new OrderBindingModel {
                    ID = _orderId,
                    ClientID = view.ClientID,
                    DateCreate = view.DateCreate,
                    ProductList = _productlist,
                    Sum = Calc(_productlist)
                };
                var operationResult = _order.DeleteProduct(model);
                if (!operationResult) {
                    throw new Exception("Ошибка при сохранении, дополнительная информация в логах");
                }
            }
            catch (Exception ex) {
                _logger.LogError(ex, "Ошибка");
                throw;
            }
        }

        [HttpPost]
        public double Calc(Dictionary<int, (IProductModel, int)> _productlist) {
            double ans = 0;
            foreach (var item in _productlist) {
                ans += item.Value.Item1.Price * item.Value.Item2;
            }
            return ans;
        }

		[HttpPost]
		public List<PaymeantViewModel>? GetPaymeants(int _clientID) {
			try {
				return _paymeant.ReadList(new PaymeantSearchModel { ClientID = _clientID });
			}
			catch (Exception ex) {
				_logger.LogError(ex, $"Ошибка получения списка оплат клиента id = {_clientID}");
				throw;
			}
		}
	}
}