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 UserBusinessLogicContract : IUserBusinessLogicContract
{
    private readonly ILogger<UserBusinessLogicContract> _logger;
    private readonly IUserStorageContract _userStorage;

    public UserBusinessLogicContract(ILogger<UserBusinessLogicContract> logger, IUserStorageContract userStorage)
    {
        _logger = logger;
        _userStorage = userStorage;
    }

    public List<UserViewModel>? ReadList(UserBindingModel? model)
    {
        _logger.LogInformation("ReadList for user: {Login}", model?.Login);

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

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

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

        _logger.LogInformation("ReadElement for user: {Login}", model.Login);
        try
        {
            var element = _userStorage.GetElement(model);
            _logger.LogInformation("ReadElement found: {Login}", element.Login);
            return element;
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "ReadElement: User not found for login: {Login}", model.Login);
            return null;
        }
    }

    public void Create(UserBindingModel model)
    {
        CheckModel(model);
        try
        {
            _userStorage.Insert(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Insert operation failed for user: {Login}", model.Login);
            throw new Exception("Insert operation failed", ex);
        }
    }

    public void Update(UserBindingModel model)
    {
        CheckModel(model);
        try
        {
            _userStorage.Update(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Update operation failed for user: {Login}", model.Login);
            throw new Exception("Update operation failed", ex);
        }
    }

    public void Delete(UserBindingModel model)
    {
        CheckModel(model, false);
        _logger.LogInformation("Delete. Login: {Login}", model.Login);
        try
        {
            _userStorage.Delete(model);
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Delete operation failed for user: {Login}", model.Login);
            throw new Exception("Delete operation failed", ex);
        }
    }

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

        if (!withParams)
        {
            return;
        }

        if (string.IsNullOrEmpty(model.Login))
        {
            throw new ArgumentNullException("Логин обязателен", nameof(model.Login));
        }

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

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

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

        if (!model.Password.Any(char.IsLetter) || !model.Password.Any(char.IsDigit))
        {
            throw new ArgumentException("Пароль должен содержать хотя бы одну букву и одну цифру", nameof(model.Password));
        }

        if (string.IsNullOrEmpty(model.FIO))
        {
            throw new ArgumentNullException("ФИО обязательно", nameof(model.FIO));
        }

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

        if (string.IsNullOrEmpty(model.Email))
        {
            throw new ArgumentNullException("Email обязателен", nameof(model.Email));
        }

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

        if (!new System.ComponentModel.DataAnnotations.EmailAddressAttribute().IsValid(model.Email))
        {
            throw new ArgumentException("Некорректный формат email", nameof(model.Email));
        }

        _logger.LogInformation("User validation passed for: {Login}", model.Login);

        var existingUserByLogin = _userStorage.GetElement(new UserBindingModel { Login = model.Login });
        var existingUserByEmail = _userStorage.GetElement(new UserBindingModel { Email = model.Email });

        if (existingUserByLogin != null && existingUserByLogin.ID != (model.Id ?? 0))
        {
            throw new InvalidOperationException($"Пользователь с логином {model.Login} уже существует");
        }

        if (existingUserByEmail != null && existingUserByEmail.ID != (model.Id ?? 0))
        {
            throw new InvalidOperationException($"Пользователь с email {model.Email} уже существует");
        }
    }
}