using MarketPriceLookup.Helpers;
using Microsoft.VisualBasic.FileIO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;

namespace MarketPriceLookup.Common.Helpers
{
    public static class MarketPricesHelper
    {
        private static readonly Dictionary<string, Prices> priceFile = new Dictionary<string, Prices>();

        public static Dictionary<string, Prices> GetAllPrices()
        {
            if (priceFile.Count == 0)
            {
                //HydrateDictionaryCSV();
                HydrateDictionaryTarkovDev();
            }

            return priceFile;
        }

        private static void HydrateDictionaryTarkovDev()
        {
            var request = new Dictionary<string, string>()
            {
                {"query", "{  items(lang: en) {    name    avg24hPrice    changeLast48hPercent    id historicalPrices{ price timestamp }  }}"}
            };

            using (var httpClient = new HttpClient())
            {
                // call tarkov dev api
                var httpResponse = httpClient.PostAsJsonAsync("https://api.tarkov.dev/graphql", request).GetAwaiter().GetResult();
                var responseContent = httpResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                var parsedResponse = JsonSerializer.Deserialize<TarkovDevResponse>(responseContent, new JsonSerializerOptions());

                // iterate over all items returned and filter out bad prices
                foreach (var item in parsedResponse.data.items)
                {
                    if (item.historicalPrices.Length == 0)
                    {
                        LoggingHelpers.LogError($"unable to add item {item.id} {item.name} with no historical prices, ignoring");
                        continue;
                    }

                    if (item.changeLast48hPercent > 100)
                    {
                        LoggingHelpers.LogWarning($"Item {item.id} {item.name} Has had recent {item.changeLast48hPercent}% increase in price. {item.historicalPrices.Length} price values");
                    }

                    var averagedItemPrice = GetAveragedPrice(item);
                    if (averagedItemPrice == 0)
                    {
                        LoggingHelpers.LogError($"unable to add item {item.id} {item.name} with average price of 0, ignoring");
                        continue;
                    }

                    if (item.name.Contains(" (0/"))
                    {
                        LoggingHelpers.LogWarning($"Skipping 0 durability item: {item.id} {item.name}");
                        continue;
                    }

                    if (priceFile.ContainsKey(item.id))
                    {
                        // Item already exists in the csv
                        var existingItem = priceFile[item.id];
                        LoggingHelpers.LogError($"Unable to add item: {item.id} {item.name} (price: {item.avg24hPrice}). existing item: {existingItem.TemplateId} {existingItem.Name} (price: {existingItem.Average24hPrice})");
                        if (existingItem.Average24hPrice < averagedItemPrice)
                        {
                            LoggingHelpers.LogError($"Price diff found: existing item price: {existingItem.Average7DaysPrice} new item price: {averagedItemPrice}, using larger price");
                            priceFile.Remove(item.id);
                        }
                    }

                    // Item not already in dictionary, add it
                    if (!priceFile.ContainsKey(item.id))
                    {
                        priceFile.Add(item.id, new Prices
                        {
                            Name = item.name,
                            //Price = price,
                            Average24hPrice = item.avg24hPrice,
                            Average7DaysPrice = averagedItemPrice,
                            //Trader = trader,
                            //BuyPackPrice = buyBackPrice,
                            //Currency = currency,
                            TemplateId = item.id,
                            //TraderPrice = traderPrice,
                        });

                        LoggingHelpers.LogSuccess($"Adding item: {item.id} {item.name}");
                    }
                }
            }
        }

        /// <summary>
        /// Get items average flea price from all readings taken over the past 7 days
        /// </summary>
        /// <param name="item"></param>
        private static int GetAveragedPrice(Item item)
        {
            var sevenDaysAgoTimestamp = DateTimeOffset.UtcNow.AddDays(-7).ToUnixTimeSeconds();
            var pricesWithinLast7days = new List<int>();
            foreach (var historicalPrice in item.historicalPrices)
            {
                if (long.Parse(historicalPrice.timestamp) > sevenDaysAgoTimestamp)
                {
                    pricesWithinLast7days.Add(historicalPrice.price);
                }
            }

            if (pricesWithinLast7days.Count == 0)
            {
                LoggingHelpers.LogError($"No prices found for item {item.name} in last 7 days, using any availible");
                pricesWithinLast7days.AddRange(item.historicalPrices.Select(x => x.price));
            }

            return (int)Math.Round(pricesWithinLast7days.Average());
        }

        public static Prices GetItemPrice(string key)
        {
            // parse csv if dictionary is empty
            if (priceFile.Count == 0)
            {
                //HydrateDictionaryCSV();
                HydrateDictionaryTarkovDev();
            }

            if (!priceFile.ContainsKey(key))
            {
                return null;
            }

            return priceFile[key];
        }

        private static void HydrateDictionaryCSV()
        {
            var workingPath = Directory.GetCurrentDirectory();
            var inputPath = $"{workingPath}//input";
            var filePath = $"{inputPath}//marketPrices.csv";
            DiskHelpers.CreateDirIfDoesntExist(inputPath);

            using (TextFieldParser csvParser = new TextFieldParser(filePath))
            {
                csvParser.CommentTokens = new string[] { "#" };
                csvParser.SetDelimiters(new string[] { "," });
                csvParser.HasFieldsEnclosedInQuotes = true;

                // Skip the row with the column names
                csvParser.ReadLine();
                csvParser.ReadLine();

                while (!csvParser.EndOfData)
                {
                    // Read current line fields, pointer moves to the next line.
                    string[] fields = csvParser.ReadFields();
                    //string uid = fields[0];
                    string name = fields[1];
                    int price = int.Parse(fields[2]);
                    int avg24hPrice = int.Parse(fields[3]);
                    int avg7daysPrice = int.Parse(fields[4]);
                    string trader = fields[5];
                    //int buyBackPrice = int.Parse(fields[6]);
                    string currency = GetCurrencyType(fields[7]);
                    string bsgId = fields[8];
                    int traderPrice = int.Parse(fields[9]);

                    if (avg7daysPrice == 0)
                    {
                        LoggingHelpers.LogError($"unable to add item {bsgId} {name} with average price of 0, ignoring");
                        continue;
                    }

                    if (name.Contains(" (0/"))
                    {
                        LoggingHelpers.LogWarning($"Skipping 0 durability item: {bsgId} {name}");
                        continue;
                    }

                    if (priceFile.ContainsKey(bsgId))
                    {
                        //oh no, item already exists in the csv
                        var existingItem = priceFile[bsgId];
                        LoggingHelpers.LogError($"Unable to add item: {bsgId} {name}. existing item: {existingItem.TemplateId} {existingItem.Name}");
                        if (existingItem.Average7DaysPrice < avg7daysPrice)
                        {
                            LoggingHelpers.LogError($"Price diff found: existing item price: {existingItem.Average7DaysPrice} new item price: {avg7daysPrice}, using larger price");
                            priceFile.Remove(bsgId);
                        }
                    }
                    if (!priceFile.ContainsKey(bsgId))
                    {
                        priceFile.Add(bsgId, new Prices
                        {
                            Name = name,
                            Price = price,
                            Average24hPrice = avg24hPrice,
                            Average7DaysPrice = avg7daysPrice,
                            Trader = trader,
                            //BuyPackPrice = buyBackPrice,
                            Currency = currency,
                            TemplateId = bsgId,
                            TraderPrice = traderPrice,
                        });
                    }

                    LoggingHelpers.LogSuccess($"Adding item: {bsgId} {name}");

                }
            }
        }

        private static string GetCurrencyType(string input)
        {
            return input switch
            {
                "₽" => "Rouble",
                "$" => "Dollar",
                "€" => "Euro",
                _ => string.Empty,
            };
        }
    }
}