using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Users;
using Microsoft.Extensions.Logging;

namespace Managing.Application.MoneyManagements;

public class MoneyManagementService : IMoneyManagementService
{
    private readonly ISettingsRepository _settingsRepository;
    private readonly ILogger<MoneyManagementService> _logger;

    public MoneyManagementService(
        ILogger<MoneyManagementService> logger,
        ISettingsRepository settingsRepository)
    {
        _logger = logger;
        _settingsRepository = settingsRepository;
    }

    public async Task<MoneyManagement> CreateOrUpdateMoneyManagement(User user, MoneyManagement request)
    {
        // Try to get user-specific strategy first
        var moneyManagement = await _settingsRepository.GetMoneyManagementByUser(user, request.Name);

        // Fall back to regular lookup if user-specific endpoint is not implemented
        if (moneyManagement == null)
        {
            moneyManagement = await _settingsRepository.GetMoneyManagement(request.Name);

            // If found by name but doesn't belong to this user, treat as new
            if (moneyManagement != null && moneyManagement.User?.Name != user.Name)
            {
                moneyManagement = null;
            }
        }

        if (moneyManagement == null)
        {
            // Convert MoneyManagement to LightMoneyManagement for insertion
            var lightRequest = new LightMoneyManagement
            {
                Name = request.Name,
                Timeframe = request.Timeframe,
                StopLoss = request.StopLoss,
                TakeProfit = request.TakeProfit,
                Leverage = request.Leverage
            };

            await _settingsRepository.InsertMoneyManagement(lightRequest, user);

            // Return the created money management with user
            return new MoneyManagement
            {
                Name = lightRequest.Name,
                Timeframe = lightRequest.Timeframe,
                StopLoss = lightRequest.StopLoss,
                TakeProfit = lightRequest.TakeProfit,
                Leverage = lightRequest.Leverage,
                User = user
            };
        }
        else
        {
            // Additional check to ensure user's ownership
            if (moneyManagement.User?.Name != user.Name)
            {
                throw new UnauthorizedAccessException(
                    "You do not have permission to update this money management strategy.");
            }

            // Convert to LightMoneyManagement for update
            var lightRequest = new LightMoneyManagement
            {
                Name = request.Name,
                Timeframe = request.Timeframe,
                StopLoss = request.StopLoss,
                TakeProfit = request.TakeProfit,
                Leverage = request.Leverage
            };

            await _settingsRepository.UpdateMoneyManagementAsync(lightRequest, user);

            // Return updated money management
            return new MoneyManagement
            {
                Name = lightRequest.Name,
                Timeframe = lightRequest.Timeframe,
                StopLoss = lightRequest.StopLoss,
                TakeProfit = lightRequest.TakeProfit,
                Leverage = lightRequest.Leverage,
                User = user
            };
        }
    }

    public async Task<MoneyManagement> GetMoneyMangement(string name)
    {
        return await _settingsRepository.GetMoneyManagement(name);
    }

    public async Task<IEnumerable<MoneyManagement>> GetMoneyMangements(User user)
    {
        try
        {
            // Try to use user-specific repository method first
            return await _settingsRepository.GetMoneyManagementsByUserAsync(user);
        }
        catch
        {
            // Fall back to filtering if user-specific endpoint is not implemented
            var allMoneyManagements = await _settingsRepository.GetMoneyManagementsAsync();
            return allMoneyManagements.Where(mm => mm.User?.Name == user.Name);
        }
    }

    public async Task<MoneyManagement> GetMoneyMangement(User user, string name)
    {
        MoneyManagement moneyManagement;

        try
        {
            // Try to use user-specific repository method first
            moneyManagement = await _settingsRepository.GetMoneyManagementByUser(user, name);
        }
        catch
        {
            // Fall back to regular lookup if user-specific endpoint is not implemented
            moneyManagement = await _settingsRepository.GetMoneyManagement(name);

            // Filter by user
            if (moneyManagement != null && moneyManagement.User?.Name != user.Name)
            {
                moneyManagement = null;
            }
        }

        return moneyManagement;
    }

    public async Task<bool> DeleteMoneyManagement(User user, string name)
    {
        try
        {
            try
            {
                // Try to use user-specific repository method first
                await _settingsRepository.DeleteMoneyManagementByUserAsync(user, name);
            }
            catch
            {
                // Fall back to verifying user ownership before deletion
                var moneyManagement = await _settingsRepository.GetMoneyManagement(name);

                if (moneyManagement != null && moneyManagement.User?.Name != user.Name)
                {
                    throw new UnauthorizedAccessException(
                        "You do not have permission to delete this money management strategy.");
                }

                await _settingsRepository.DeleteMoneyManagementAsync(name);
            }

            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message);
            return false;
        }
    }

    public async Task<bool> DeleteMoneyManagements(User user)
    {
        try
        {
            try
            {
                // Try to use user-specific repository method first
                await _settingsRepository.DeleteMoneyManagementsByUserAsync(user);
            }
            catch
            {
                // This fallback is not ideal as it would delete all money managements regardless of user
                // In a real implementation, we would need a filtered repository method
                _logger.LogWarning(
                    "DeleteMoneyManagementsByUser not implemented, cannot delete user-specific money managements");
            }

            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message);
            return false;
        }
    }
}