using Knoks.Core.Data.Dao;
using Knoks.Core.Data.Interfaces;
using Knoks.Core.Entities;
using Knoks.Core.Logic.Interfaces;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Knoks.Core.Logic.Managers
{
    public class ExchangeManager : IExchangeManager
    {
        private readonly ILogger<ExchangeManager> _logger;
        private readonly IExchangeDao _exchangeDao;
        private readonly IDictionary<int, IExchange> _exchanges;
        private readonly IKnokSettings _settings;

        public ExchangeManager(ILogger<ExchangeManager> logger, IExchangeDao exchangeDao, IKnokSettings _settings, IDictionary<int, IExchange> exchanges) {
            this._exchangeDao = exchangeDao;
            this._exchanges = exchanges;
            this._settings = _settings;
            this._logger = logger;
        }

        public async Task UpdateExchanges()
        {
            System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
            if (System.Net.ServicePointManager.ServerCertificateValidationCallback == null)
            {
                System.Net.ServicePointManager.ServerCertificateValidationCallback = ((s, c, c2, se) => true);
            }


            await Task.WhenAll(_exchanges.Select(async it =>
            {
                try {
                    var data = await it.Value.GetMarkets();
                    await _exchangeDao.SaveTickers(it.Key, data);
                }
                catch (Exception ex) {
                    this._logger.LogError(ex, $"UpdateExchanges error for ExchangeId: {it.Key}");
                }
            }));
        }

        public async Task<ExchangeStart> GetTradingPairRate(int exchangeId, string currency1, string currency2)
        {
            System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
            if (System.Net.ServicePointManager.ServerCertificateValidationCallback == null)
            {
                System.Net.ServicePointManager.ServerCertificateValidationCallback = ((s, c, c2, se) => true);
            }

            return await Task<ExchangeStart>.Run(() =>
              {
                  try
                  {
                      TickerInfo ticker = _exchangeDao.GetTicker(exchangeId, currency1, currency2).GetAwaiter().GetResult();
                      var exchange = _exchanges[ticker.ExchangeId];
                      var tickerData = exchange.GetTickerData(ticker, DateTime.UtcNow.AddMinutes(-15), DateTime.UtcNow.AddMinutes(15)).GetAwaiter().GetResult();
                      if (tickerData != null)
                      {
                          var minVal = (decimal)(1 / Math.Pow(10, ticker.Decimals));
                          var exchangeStart = new ExchangeStart();
                          //1.Entry from = current price from the relevant exchange
                          var val = tickerData.Close ?? 0m;
                          exchangeStart.EntryFrom = val;

                          //2.Entry to = Entry from + minimum spread for entry(%)
                          val = Math.Round( val + ((val / 100m) * _settings.MinEntrySpread), ticker.Decimals);
                          exchangeStart.EntryTo = val;
                          
                          //3.Exit from = Entry to + minimum high spread for entry (%)
                          val = Math.Round(val + ((val / 100m) * _settings.MinHighEntrySpread), ticker.Decimals);
                          exchangeStart.ExitFrom = val;

                          //4.Exit to = Exit from + minimum spread for exit (%)
                          val = Math.Round(val + ((val / 100m) * _settings.MinExitSpread), ticker.Decimals);
                          exchangeStart.ExitTo = val;

                          //5.SL = Entry from - highest possible SL
                          val = Math.Round( (tickerData.Close ?? 0m) - minVal, ticker.Decimals);
                          exchangeStart.StopLoss = val;

                          exchangeStart.Precision = (short)ticker.Decimals;

                          return exchangeStart;
                      }
                      return new ExchangeStart();
                  }
                  catch(Exception ex)
                  {
                      this._logger.LogError(ex, $"GetTradingPairRate error for ExchangeId: {exchangeId}. Pair: \"{currency1}-{currency2}\"");
                      return new ExchangeStart();
                  }
              });
        }

        public async Task PutDataExchanges(TickerData data)
        {
                await _exchangeDao.SaveExchanges(data);
        }

        /*public async Task UpdateTickers() {
            GetUsedInKnoksTickers
            RequestTickerData
        }*/
        public async Task<TickerData> GetTickerData(int tickerId, DateTime start, DateTime end)
        {
            try
            {
                TickerInfo ticker = await _exchangeDao.GetTicker(tickerId);
                var exchange = _exchanges[ticker.ExchangeId];
                return await exchange.GetTickerData(ticker, start, end);
            }
            catch (Exception ex)
            {
                this._logger.LogError(ex, $"GetTickerData error for TickerId: {tickerId}. Date: \"{start}-{end}\"");
                return new TickerData();
            }
        }

        public async Task<TickerData> GetTickerData(int exchangeId, string currency1, string currency2)
        {
            try
            {
                TickerInfo ticker = await _exchangeDao.GetTicker(exchangeId, currency1, currency2);
                var exchange = _exchanges[ticker.ExchangeId];
                return await exchange.GetTickerData(ticker, DateTime.UtcNow.AddMinutes(-15), DateTime.UtcNow.AddMinutes(15));
            }
            catch (Exception ex)
            {
                this._logger.LogError(ex, $"GetTickerData error for ExchangeId: {exchangeId}. Pair: \"{currency1}-{currency2}\"");
                return new TickerData();
            }
        }

        /*public async Task<IEnumerable<TickerData>> RequestTickerData(int tickerId, DateTime start, DateTime end) {
            TickerInfo ticker = await exchangeDao.GetTicker(tickerId);
            var exchange = exchanges[ticker.ExchangeId];

            if (ticker.TickerActive && ticker.TickerEnd < start)
            {
                if (ticker.TickerGot != ticker.TickerEnd) {
                    Save(await exchange.GetTickerData(ticker, ticker.TickerGot, ticker.TickerEnd));
                    //ticker.TickerGot = ticker.TickerEnd;
                    ticker.TickerStart = ticker.TickerGot = start;
                    ticker.TickerEnd = end;
                }
            }
            DateTime loadStart;
            if (ticker.TickerActive) {
                loadStart = new List<DateTime>() { ticker.TickerGot, start }.Min();
            }
            else {
                ticker.TickerActive = true;
                loadStart = ticker.TickerStart = ticker.TickerGot = start;
                ticker.TickerEnd = new List<DateTime>() { ticker.TickerEnd, end }.Max();
            }
            Save(await exchange.GetTickerData(ticker, loadStart, new List<DateTime>() { ticker.TickerEnd, DateTime.UtcNow }.Min());
            if (ticker.TickerEnd < DateTime.UtcNow) {
                ticker.TickerActive = false;
            }
            //tickerSave
            //exchangeDao.SaveTickerInfo();
        }

        private void Save(IEnumerable<TickerData> data)
        {
            var list = data.ToList();
            foreach (var val in list)
            {
                exchangeDao.SaveTickerData(val);
            }
        }
        */
    }
}
