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 ComponentBusinessLogicContract : IComponentBusinessLogicContract
{
    private readonly ILogger<ComponentBusinessLogicContract> _logger;
    private readonly IComponentStorageContract _componentStorage;

    public ComponentBusinessLogicContract(ILogger<ComponentBusinessLogicContract> logger, IComponentStorageContract componentStorage)
    {
        _logger = logger;
        _componentStorage = componentStorage;
    }

    public List<ComponentViewModel>? ReadList(ComponentBindingModel? model)
    {
        _logger.LogInformation("ReadList for component. UserID: {UserID}", model?.UserID);

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

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

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

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

    public void Create(ComponentBindingModel model)
    {
        CheckModel(model);
        try
        {
            _componentStorage.Insert(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Insert operation failed for component: {ComponentName}", model.ComponentName);
            throw new Exception("Insert operation failed", ex);
        }
    }

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

    public void Delete(ComponentBindingModel model)
    {
        CheckModel(model, false);
        _logger.LogInformation("Delete. Component: {Id}", model.Id);
        try
        {
            _componentStorage.Delete(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Delete operation failed for component: {Id}", model.Id);
            throw new Exception("Delete operation failed", ex);
        }
    }

    public List<ComponentRequestAssemblyReportViewModel>? GetComponentsReport(DateTime startDate, DateTime endDate, int userId)
    {
        _logger.LogInformation("Generating components report for user: {UserID}, Period: {StartDate} - {EndDate}", userId, startDate, endDate);

        try
        {
            var report = _componentStorage.GetComponentsReport(startDate, endDate, userId);
            if (report == null)
            {
                _logger.LogWarning("GetComponentsReport returned null. Returning empty list instead.");
                return new List<ComponentRequestAssemblyReportViewModel>();
            }

            _logger.LogInformation("Components report generated. Count: {Count}", report.Count);
            return report;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error generating components report for user: {UserID}", userId);
            return new List<ComponentRequestAssemblyReportViewModel>();
        }
    }

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

        if (!withParams)
        {
            return;
        }

        if (string.IsNullOrEmpty(model.ComponentName))
        {
            throw new ArgumentNullException("Название комплектующего обязательно", nameof(model.ComponentName));
        }

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

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

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

        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("Component validation passed for: {ComponentName}", model.ComponentName);

        var existingComponent = _componentStorage.GetElement(new ComponentBindingModel { ComponentName = model.ComponentName });
        if (existingComponent != null && existingComponent.Id != (model.Id ?? 0))
        {
            throw new InvalidOperationException($"Комплектующее с названием {model.ComponentName} уже существует");
        }
    }
}