using ComputerStoreContracts.BindingModels;
using ComputerStoreContracts.BusinessLogicContracts;
using ComputerStoreContracts.StoragesContracts;
using ComputerStoreContracts.ViewModels;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ComputerStoreBusinessLogic.Implementations;

public class ProductBusinessLogicContract : IProductBusinessLogicContract
{
    private readonly ILogger<ProductBusinessLogicContract> _logger;
    private readonly IProductStorageContract _productStorage;

    public ProductBusinessLogicContract(ILogger<ProductBusinessLogicContract> logger, IProductStorageContract productStorage)
    {
        _logger = logger;
        _productStorage = productStorage;
    }

    public List<ProductViewModel>? ReadList(ProductBindingModel? model)
    {
        _logger.LogInformation("ReadList for product. UserID: {UserID}", model?.UserID);

        List<ProductViewModel> list;
        try
        {
            list = model == null ? _productStorage.GetFullList() : _productStorage.GetFilteredList(model);
            if (list == null)
            {
                _logger.LogWarning("GetFullList/GetFilteredList returned null. Returning empty list instead.");
                list = new List<ProductViewModel>();
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error retrieving product list from storage.");
            return new List<ProductViewModel>();
        }

        _logger.LogInformation("ReadList. Count: {Count}", list.Count);
        return list;
    }

    public ProductViewModel? ReadElement(ProductBindingModel model)
    {
        if (model == null)
        {
            throw new ArgumentNullException(nameof(model));
        }

        _logger.LogInformation("ReadElement for product: {Id}, UserID: {UserID}", model.Id, model.UserID);
        try
        {
            var element = _productStorage.GetElement(model);
            _logger.LogInformation("ReadElement found: {Id}", element.Id);
            return element;
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "ReadElement: Product not found for ID: {Id}", model.Id);
            return null;
        }
    }

    public void Create(ProductBindingModel model)
    {
        CheckModel(model);
        try
        {
            _productStorage.Insert(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Insert operation failed for product: {Name}", model.Name);
            throw new Exception("Insert operation failed", ex);
        }
    }

    public void Update(ProductBindingModel model)
    {
        CheckModel(model);
        try
        {
            _productStorage.Update(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Update operation failed for product: {Id}", model.Id);
            throw new Exception("Update operation failed", ex);
        }
    }

    public void Delete(ProductBindingModel model)
    {
        CheckModel(model, false);
        _logger.LogInformation("Delete. Product: {Id}", model.Id);
        try
        {
            _productStorage.Delete(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Delete operation failed for product: {Id}", model.Id);
            throw new Exception("Delete operation failed", ex);
        }
    }

    private void CheckModel(ProductBindingModel model, bool withParams = true)
    {
        if (model == null)
        {
            throw new ArgumentNullException(nameof(model));
        }

        if (!withParams)
        {
            return;
        }

        if (string.IsNullOrEmpty(model.Name))
        {
            throw new ArgumentNullException("Название товара обязательно", nameof(model.Name));
        }

        if (model.Name.Length > 100)
        {
            throw new ArgumentException("Название товара не должно превышать 100 символов", nameof(model.Name));
        }

        if (string.IsNullOrEmpty(model.Category))
        {
            throw new ArgumentNullException("Категория товара обязательна", nameof(model.Category));
        }

        if (model.Category.Length > 100)
        {
            throw new ArgumentException("Категория товара не должна превышать 100 символов", nameof(model.Category));
        }

        if (model.Price <= 0)
        {
            throw new ArgumentException("Цена должна быть больше 0", nameof(model.Price));
        }

        if (model.UserID <= 0)
        {
            throw new ArgumentException("ID пользователя должен быть больше 0", nameof(model.UserID));
        }

        _logger.LogInformation("Product validation passed for: {Name}", model.Name);

        var existingProduct = _productStorage.GetElement(new ProductBindingModel { Name = model.Name });
        if (existingProduct != null && existingProduct.Id != (model.Id ?? 0))
        {
            throw new InvalidOperationException($"Товар с названием {model.Name} уже существует");
        }
    }
}