using Microsoft.Extensions.Logging;
using SushiBarContracts.BindingModels;
using SushiBarContracts.BusinessLogicsContracts;
using SushiBarContracts.SearchModels;
using SushiBarContracts.StoragesContracts;
using SushiBarContracts.ViewModels;

namespace SushiBarBusinessLogic.BusinessLogics;

public class ClientLogic : IClientLogic
{
    private readonly ILogger _logger;
    private readonly IClientStorage _clientStorage;

    public ClientLogic(ILogger<ClientLogic> logger, IClientStorage clientStorage)
    {
        _logger = logger;
        _clientStorage = clientStorage;
    }

    public List<ClientViewModel>? ReadList(ClientSearchModel? model)
    {
        _logger.LogInformation("ReadList clients .FIO:{ClientFio} .EMAIL:{Email} .Id:{Id}", model?.ClientFio, model?.Email, model?.Id);
        if (model == null)
            return _clientStorage.GetFullList();
        var list = _clientStorage.GetFilteredList(model);
        _logger.LogInformation("ReadList. Count:{Count}", list.Count);
        return list;
    }

    public ClientViewModel? ReadElement(ClientSearchModel model)
    {
        if (model == null)
        {
            throw new ArgumentNullException(nameof(model));
        }
        _logger.LogInformation("ReadElement clients .FIO:{ClientFio} .EMAIL:{Email} .Id:{Id}", model.ClientFio, model.Email, model.Id);
        var element = _clientStorage.GetElement(model);
        if (element == null)
        {
            _logger.LogWarning("ReadElement element not found");
            return null;
        }
        _logger.LogInformation("ReadElement find. Id:{Id}", element.Id);
        return element;
    }

    public bool Create(ClientBindingModel model)
    {
        CheckModel(model);
        if (_clientStorage.Insert(model) != null) return true;
        _logger.LogWarning("Insert operation failed");
        return false;
    }

    public bool Update(ClientBindingModel model)
    {
        CheckModel(model);
        if (_clientStorage.Update(model) != null) return true;
        _logger.LogWarning("Update operation failed");
        return false;
    }

    public bool Delete(ClientBindingModel model)
    {
        CheckModel(model, false);
        _logger.LogInformation("Delete. Id:{Id}", model.Id);
        if (_clientStorage.Delete(model) != null) return true;
        _logger.LogWarning("Delete operation failed");
        return false;
    }

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

        if (!withParams)
        {
            return;
        }

        if (string.IsNullOrEmpty(model.ClientFio))
        {
            throw new ArgumentNullException(nameof(model.ClientFio), "FIO must be not null");
        }
        if (string.IsNullOrEmpty(model.Email))
        {
            throw new ArgumentNullException(nameof(model.Email), "EMAIL must be not null");
        }
        if (string.IsNullOrEmpty(model.Password))
        {
            throw new ArgumentNullException(nameof(model.Password), "PASSWORD must be not null");
        }
        _logger.LogInformation("Client .FIO:{ClientFio} .EMAIL:{Email} .Password:{Password} .Id:{Id}", model.ClientFio, model.Email, model.Password, model.Id);
        var client = _clientStorage.GetElement(new ClientSearchModel()
        {
            Email = model.Email
        });
        if (client != null && client.Id != model.Id)
        {
            throw new InvalidOperationException("Email is already exists");
        }
    }
}