using System.Data;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Domain.Scenarios;
using Managing.Domain.Strategies;
using Managing.Domain.Users;
using Microsoft.Extensions.Logging;
using static Managing.Common.Enums;

namespace Managing.Application.Scenarios
{
    public class ScenarioService : IScenarioService
    {
        private readonly ILogger<ScenarioService> _logger;
        private readonly ITradingService _tradingService;

        public ScenarioService(ILogger<ScenarioService> logger, ITradingService tradingService)
        {
            _logger = logger;
            _tradingService = tradingService;
        }

        public async Task<Scenario> CreateScenario(string name, List<string> strategies, int? loopbackPeriod = 1)
        {
            var scenario = new Scenario(name, loopbackPeriod);

            foreach (var strategy in strategies)
            {
                scenario.AddIndicator(await _tradingService.GetIndicatorByNameAsync(strategy));
            }

            try
            {
                await _tradingService.InsertScenarioAsync(scenario);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                throw new Exception("Cannot create scenario");
            }

            return scenario;
        }

        public async Task<IEnumerable<Scenario>> GetScenariosAsync()
        {
            return await _tradingService.GetScenariosAsync();
        }

        public async Task<IEnumerable<IndicatorBase>> GetIndicatorsAsync()
        {
            return await _tradingService.GetIndicatorsAsync();
        }

        public async Task<bool> DeleteScenarioAsync(string name)
        {
            try
            {
                await _tradingService.DeleteScenarioAsync(name);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                return false;
            }
        }

        public async Task<bool> UpdateScenario(string name, List<string> strategies, int? loopbackPeriod)
        {
            try
            {
                var scenario = await _tradingService.GetScenarioByNameAsync(name);
                scenario.Indicators.Clear();
                foreach (var strategy in strategies)
                {
                    scenario.AddIndicator(await _tradingService.GetIndicatorByNameAsync(strategy));
                }

                scenario.LoopbackPeriod = loopbackPeriod ?? 1;
                await _tradingService.UpdateScenarioAsync(scenario);
                return true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
        }

        public async Task<bool> UpdateStrategy(IndicatorType indicatorType, string name, int? period, int? fastPeriods,
            int? slowPeriods,
            int? signalPeriods, double? multiplier, int? stochPeriods, int? smoothPeriods, int? cyclePeriods)
        {
            try
            {
                var strategy = await _tradingService.GetIndicatorByNameAsync(name);
                strategy.Type = indicatorType;
                strategy.Period = period;
                strategy.FastPeriods = fastPeriods;
                strategy.SlowPeriods = slowPeriods;
                strategy.SignalPeriods = signalPeriods;
                strategy.Multiplier = multiplier;
                strategy.StochPeriods = stochPeriods;
                strategy.SmoothPeriods = smoothPeriods;
                strategy.CyclePeriods = cyclePeriods;
                await _tradingService.UpdateIndicatorAsync(strategy);
                return true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
        }

        public async Task<IEnumerable<Scenario>> GetScenariosByUserAsync(User user)
        {
            return await _tradingService.GetScenariosByUserAsync(user);
        }

        public async Task<Scenario> CreateScenarioForUser(User user, string name, List<string> strategies,
            int? loopbackPeriod = 1)
        {
            var scenario = new Scenario(name, loopbackPeriod ?? 1)
            {
                User = user
            };

            foreach (var strategyName in strategies)
            {
                var strategy = await _tradingService.GetIndicatorByNameAsync(strategyName);
                if (strategy != null && strategy.User?.Name == user.Name)
                {
                    scenario.AddIndicator(strategy);
                }
            }

            await _tradingService.InsertScenarioAsync(scenario);
            return scenario;
        }

        public async Task<IEnumerable<IndicatorBase>> GetIndicatorsByUserAsync(User user)
        {
            var indicators = await GetIndicatorsAsync();
            return indicators.Where(s => s.User?.Name == user.Name);
        }

        public async Task<bool> DeleteIndicatorByUser(User user, string name)
        {
            var strategy = await _tradingService.GetIndicatorByNameAsync(name);
            if (strategy != null && strategy.User?.Name == user.Name)
            {
                await _tradingService.DeleteIndicatorAsync(strategy.Name);
                return true;
            }

            return false;
        }

        public async Task<bool> DeleteScenarioByUser(User user, string name)
        {
            try
            {
                var scenarios = await GetScenariosByUserAsync(user);
                foreach (var scenario in scenarios.Where(s => s.Name == name))
                {
                    await _tradingService.DeleteScenarioAsync(scenario.Name);
                }

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

        public async Task<bool> DeleteScenariosByUser(User user)
        {
            try
            {
                var scenarios = await GetScenariosByUserAsync(user);
                foreach (var scenario in scenarios)
                {
                    await _tradingService.DeleteScenarioAsync(scenario.Name);
                }

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

        public async Task<Scenario> GetScenarioByUser(User user, string name)
        {
            var scenario = await _tradingService.GetScenarioByNameAsync(name);
            return scenario != null && scenario.User?.Name == user.Name ? scenario : null;
        }

        public async Task<IndicatorBase> CreateIndicatorForUser(User user, IndicatorType type, string name,
            int? period = null,
            int? fastPeriods = null, int? slowPeriods = null, int? signalPeriods = null,
            double? multiplier = null, int? stochPeriods = null, int? smoothPeriods = null,
            int? cyclePeriods = null)
        {
            var existingIndicator = await _tradingService.GetIndicatorByNameUserAsync(name, user);

            if (existingIndicator != null)
            {
                throw new DuplicateNameException("An indicator with this name already exists for the user.");
            }
            else
            {
                var indicator = new IndicatorBase(name, type)
                {
                    Period = period,
                    FastPeriods = fastPeriods,
                    SlowPeriods = slowPeriods,
                    SignalPeriods = signalPeriods,
                    Multiplier = multiplier,
                    StochPeriods = stochPeriods,
                    SmoothPeriods = smoothPeriods,
                    CyclePeriods = cyclePeriods,
                    User = user
                };
                await _tradingService.InsertIndicatorAsync(indicator);
                return indicator;
            }
        }

        public async Task<bool> DeleteStrategiesByUser(User user)
        {
            try
            {
                var strategies = await GetIndicatorsByUserAsync(user);
                foreach (var strategy in strategies)
                {
                    await _tradingService.DeleteIndicatorAsync(strategy.Name);
                }

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

        public async Task<bool> UpdateScenarioByUser(User user, string name, List<string> strategies,
            int? loopbackPeriod)
        {
            var scenario = await _tradingService.GetScenarioByNameAsync(name);
            if (scenario == null || scenario.User?.Name != user.Name)
            {
                return false;
            }

            scenario.Indicators.Clear();
            scenario.LoopbackPeriod = loopbackPeriod ?? 1;

            foreach (var strategyName in strategies)
            {
                var strategy = await _tradingService.GetIndicatorByNameAsync(strategyName);
                if (strategy != null && strategy.User?.Name == user.Name)
                {
                    scenario.AddIndicator(strategy);
                }
            }

            await _tradingService.UpdateScenarioAsync(scenario);
            return true;
        }

        public async Task<bool> UpdateIndicatorByUser(User user, IndicatorType indicatorType, string name, int? period,
            int? fastPeriods, int? slowPeriods, int? signalPeriods, double? multiplier,
            int? stochPeriods, int? smoothPeriods, int? cyclePeriods)
        {
            var strategy = await _tradingService.GetIndicatorByNameAsync(name);
            if (strategy == null || strategy.User?.Name != user.Name)
            {
                return false;
            }

            // Use the existing update strategy logic
            var result = await UpdateStrategy(indicatorType, name, period, fastPeriods, slowPeriods,
                signalPeriods, multiplier, stochPeriods, smoothPeriods, cyclePeriods);

            return result;
        }

        public async Task<Scenario> GetScenarioByNameAndUserAsync(string scenarioName, User user)
        {
            var scenario = await _tradingService.GetScenarioByNameUserAsync(scenarioName, user);
            if (scenario == null)
            {
                throw new InvalidOperationException($"Scenario {scenarioName} not found for user {user.Name}");
            }

            return scenario;
        }
    }
}