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 RequestBusinessLogicContract : IRequestBusinessLogicContract
{
    private readonly ILogger<RequestBusinessLogicContract> _logger;
    private readonly IRequestStorageContract _requestStorage;

    public RequestBusinessLogicContract(ILogger<RequestBusinessLogicContract> logger, IRequestStorageContract requestStorage)
    {
        _logger = logger;
        _requestStorage = requestStorage;
    }

    public List<RequestViewModel>? ReadList(RequestBindingModel? model)
    {
        _logger.LogInformation("ReadList for request. UserID: {UserID}", model?.UserID);

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

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

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

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

    public void Create(RequestBindingModel model)
    {
        CheckModel(model);
        try
        {
            _requestStorage.Insert(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Insert operation failed for request: {Id}", model.Id);
            throw new Exception("Insert operation failed", ex);
        }
    }

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

    public void Delete(RequestBindingModel model)
    {
        CheckModel(model, false);
        _logger.LogInformation("Delete. Request: {Id}", model.Id);
        try
        {
            _requestStorage.Delete(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Delete operation failed for request: {Id}", model.Id);
            throw new Exception("Delete operation failed", ex);
        }
    }

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

        if (!withParams)
        {
            return;
        }

        if (model.DateRequest == default)
        {
            throw new ArgumentNullException("Дата заявки обязательна", nameof(model.DateRequest));
        }

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

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

        _logger.LogInformation("Request validation passed for: {Id}", model.Id);
    }
}
