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 AssemblyBusinessLogicContract : IAssemblyBusinessLogicContract
{
    private readonly ILogger<AssemblyBusinessLogicContract> _logger;
    private readonly IAssemblyStorageContract _assemblyStorage;

    public AssemblyBusinessLogicContract(ILogger<AssemblyBusinessLogicContract> logger, IAssemblyStorageContract assemblyStorage)
    {
        _logger = logger;
        _assemblyStorage = assemblyStorage;
    }

    public List<AssemblyViewModel>? ReadList(AssemblyBindingModel? model)
    {
        _logger.LogInformation("ReadList for assembly. UserID: {UserID}", model?.UserID);

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

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

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

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

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

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

    public void Delete(AssemblyBindingModel model)
    {
        CheckModel(model, false);
        _logger.LogInformation("Delete. Assembly: {Id}", model.Id);
        try
        {
            _assemblyStorage.Delete(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Delete operation failed for assembly: {Id}", model.Id);
            throw new Exception("Delete operation failed", ex);
        }
    }

    private void CheckModel(AssemblyBindingModel 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.Description))
        {
            throw new ArgumentNullException("Описание сборки обязательно", nameof(model.Description));
        }

        if (model.Description.Length > 500)
        {
            throw new ArgumentException("Описание сборки не должно превышать 500 символов", nameof(model.Description));
        }

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

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

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

        var existingAssembly = _assemblyStorage.GetElement(new AssemblyBindingModel { Name = model.Name });
        if (existingAssembly != null && existingAssembly.Id != (model.Id ?? 0))
        {
            throw new InvalidOperationException($"Сборка с названием {model.Name} уже существует");
        }
    }
}
