using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Core.Main;
using Core.Helper;
using Core.Main.DataObjects.PTMagicData;
using Newtonsoft.Json;

namespace Core.MarketAnalyzer
{
  public class CoinMarketCap : BaseAnalyzer
  {
    public static string GetMarketData(PTMagicConfiguration systemConfiguration, LogHelper log)
    {
      string result = "";
      try
      {
        string baseUrl = "https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?limit=200";
        string cmcAPI = systemConfiguration.GeneralSettings.Application.CoinMarketCapAPIKey;

        log.DoLogInfo("CoinMarketCap - Getting market data...");

        Dictionary<string, dynamic> jsonObject = GetJsonFromURL(baseUrl, log, cmcAPI);

        if (jsonObject.Count > 0)
        {
          if (jsonObject["data"] != null)
          {
            log.DoLogInfo("CoinMarketCap - Market data received for " + jsonObject["data"].Count + " currencies");

            Dictionary<string, Market> markets = new Dictionary<string, Market>();

            for (int i = 0; i < jsonObject["data"].Count; i++)
            {
              if (jsonObject["data"][i]["quote"]["USD"] != null)
              {
                Market market = new Market();
                market.Position = markets.Count + 1;
                market.Name = jsonObject["data"][i]["name"].ToString();
                market.Symbol = jsonObject["data"][i]["symbol"].ToString();
                market.Price = (double)jsonObject["data"][i]["quote"]["USD"]["price"];
                market.Volume24h = (double)jsonObject["data"][i]["quote"]["USD"]["volume_24h"];
                if (!String.IsNullOrEmpty(jsonObject["data"][i]["quote"]["USD"]["percent_change_24h"].ToString()))
                {
                  market.TrendChange24h = (double)jsonObject["data"][i]["quote"]["USD"]["percent_change_24h"];
                }

                markets.Add(market.Name, market);
              }
            }

            CoinMarketCap.CheckForMarketDataRecreation(markets, systemConfiguration, log);

            DateTime fileDateTime = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, DateTime.UtcNow.Hour, DateTime.UtcNow.Minute, 0).ToUniversalTime();

            FileHelper.WriteTextToFile(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathCoinMarketCap + Path.DirectorySeparatorChar, "MarketData_" + fileDateTime.ToString("yyyy-MM-dd_HH.mm") + ".json", JsonConvert.SerializeObject(markets), fileDateTime, fileDateTime);


            log.DoLogInfo("CoinMarketCap - Market data saved.");

            FileHelper.CleanupFiles(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathCoinMarketCap + Path.DirectorySeparatorChar, systemConfiguration.AnalyzerSettings.MarketAnalyzer.StoreDataMaxHours);
            log.DoLogInfo("CoinMarketCap - Market data cleaned.");
          }
        }
      }
      catch (Exception ex)
      {
        log.DoLogCritical(ex.Message, ex);
        result = ex.Message;
      }

      return result;
    }

    public static void CheckForMarketDataRecreation(Dictionary<string, Market> markets, PTMagicConfiguration systemConfiguration, LogHelper log)
    {
      string coinMarketCapDataDirectoryPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathCoinMarketCap + Path.DirectorySeparatorChar;

      if (!Directory.Exists(coinMarketCapDataDirectoryPath))
      {
        Directory.CreateDirectory(coinMarketCapDataDirectoryPath);
      }

      DirectoryInfo dataDirectory = new DirectoryInfo(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathCoinMarketCap + Path.DirectorySeparatorChar);

      List<FileInfo> marketFiles = dataDirectory.EnumerateFiles("MarketData*")
                         .Select(x => { x.Refresh(); return x; })
                         .Where(x => x.LastWriteTimeUtc <= DateTime.UtcNow.AddHours(-24))
                         .ToArray().OrderByDescending(f => f.LastWriteTimeUtc).ToList();

      bool build24hMarketDataFile = false;
      FileInfo marketFile = null;
      if (marketFiles.Count > 0)
      {
        marketFile = marketFiles.First();
        if (marketFile.LastWriteTimeUtc <= DateTime.UtcNow.AddHours(-24).AddMinutes(-systemConfiguration.AnalyzerSettings.MarketAnalyzer.IntervalMinutes).AddSeconds(-10))
        {
          log.DoLogDebug("CoinMarketCap - 24h market data file too old (" + marketFile.LastWriteTimeUtc.ToString() + "). Rebuilding data...");
          build24hMarketDataFile = true;
        }
      }
      else
      {
        marketFiles = dataDirectory.EnumerateFiles("MarketData*")
                         .Select(x => { x.Refresh(); return x; })
                         .Where(x => x.LastWriteTimeUtc >= DateTime.UtcNow.AddHours(-24))
                         .ToArray().OrderBy(f => f.LastWriteTimeUtc).ToList();

        if (marketFiles.Count > 0)
        {
          marketFile = marketFiles.First();
          if (marketFile.LastWriteTimeUtc >= DateTime.UtcNow.AddHours(-24).AddMinutes(systemConfiguration.AnalyzerSettings.MarketAnalyzer.IntervalMinutes).AddSeconds(10))
          {
            log.DoLogDebug("CoinMarketCap - 24h market data file too young (" + marketFile.LastWriteTimeUtc.ToString() + "). Rebuilding data...");
            build24hMarketDataFile = true;
          }
        }
        else
        {
          log.DoLogDebug("CoinMarketCap - 24h market data not found. Rebuilding data...");
          build24hMarketDataFile = true;
        }
      }

      if (build24hMarketDataFile)
      {
        Dictionary<string, Market> markets24h = new Dictionary<string, Market>();
        foreach (string key in markets.Keys)
        {
          Market market24h = new Market();
          market24h.Position = markets.Count + 1;
          market24h.Name = markets[key].Name;
          market24h.Symbol = markets[key].Symbol;
          market24h.Price = markets[key].Price / (1 + (markets[key].TrendChange24h / 100));
          market24h.Volume24h = markets[key].Volume24h;

          markets24h.Add(markets[key].Name, market24h);
        }

        DateTime fileDateTime = new DateTime(DateTime.UtcNow.ToLocalTime().AddHours(-24).Year, DateTime.UtcNow.ToLocalTime().AddHours(-24).Month, DateTime.UtcNow.ToLocalTime().AddHours(-24).Day, DateTime.UtcNow.ToLocalTime().AddHours(-24).Hour, DateTime.UtcNow.ToLocalTime().AddHours(-24).Minute, 0).ToUniversalTime();

        FileHelper.WriteTextToFile(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + Constants.PTMagicPathData + Path.DirectorySeparatorChar + Constants.PTMagicPathCoinMarketCap + Path.DirectorySeparatorChar, "MarketData_" + fileDateTime.ToString("yyyy-MM-dd_HH.mm") + ".json", JsonConvert.SerializeObject(markets24h), fileDateTime, fileDateTime);


        log.DoLogInfo("CoinMarketCap - 24h market data rebuilt.");
      }
    }
  }
}