namespace MyOffice.Services.Currency;

using Core;
using Data.Models.Currencies;
using Data.Repositories.Currency;
using MyOffice.Services.Currency.Domain;

public class CurrencyService
{
	private readonly ICurrencyGlobalRepository _currencyGlobalRepository;
	private readonly ICurrencyRepository _currencyRepository;
	private readonly ICurrencyRateRepository _currencyRateRepository;

	public CurrencyService(
		ICurrencyGlobalRepository currencyGlobalRepository,
		ICurrencyRepository currencyRepository,
		ICurrencyRateRepository currencyRateRepository
	)
	{
		_currencyGlobalRepository = currencyGlobalRepository;
		_currencyRepository = currencyRepository;
		_currencyRateRepository = currencyRateRepository;
	}

	public List<CurrencyGlobal> GetGlobalAll()
	{
		return _currencyGlobalRepository.GetAll();
	}

	public List<Currency> GetAll(Guid userId)
	{
		return _currencyRepository.GetAll(userId);
	}

	public Dictionary<Currency, CurrencyRate?> GetAllWithRates(Guid userId)
	{
		var list = _currencyRepository.GetAll(userId);
		return list.ToDictionary(
			x => x,
			x => _currencyRateRepository.GetLastRates(x.Id, 1).FirstOrDefault()
		);
	}

	public Exec<Currency, AddCurrencyStatus> AddCurrency(Guid userId, Currency currency)
	{
		if (currency == null)
			throw new ArgumentNullException(nameof(currency));

		var result = new Exec<Currency, AddCurrencyStatus>(AddCurrencyStatus.success);

		var exists = _currencyRepository.GetByGlobalCurrency(userId, currency.CurrencyGlobalId);
		if (exists != null)
		{
			return result.Set(exists, AddCurrencyStatus.exists);
		}

		currency.Id = Guid.NewGuid();
		currency.UserId = userId;
		if (!_currencyRepository.Add(currency))
		{
			return result.Set(AddCurrencyStatus.failed);
		}

		return result.Set(currency);
	}

	public Exec<CurrencyRate, CurrencyAddRateStatus> AddCurrencyRate(Guid userId, Guid currencyId, CurrencyRate currencyRate)
	{
		if (currencyRate == null)
			throw new ArgumentNullException(nameof(currencyRate));

		var result = new Exec<CurrencyRate, CurrencyAddRateStatus>(CurrencyAddRateStatus.success);

		var exists = _currencyRepository.Get(userId, currencyId);
		if (exists == null)
		{
			return result.Set(CurrencyAddRateStatus.not_found);
		}

		currencyRate.CurrencyId = exists.Id;
		currencyRate.DateTime = currencyRate.DateTime.Date;

		var rate = _currencyRateRepository.GetAtDate(currencyRate.CurrencyId, currencyRate.DateTime);
		if (rate.All(x => x.Rate != currencyRate.Rate))
		{
			if (_currencyRateRepository.AddRate(currencyRate))
			{
				return result.Set(currencyRate);
			}
		}

		return result.Set(CurrencyAddRateStatus.failed);
	}
}
