using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Web;
using System.Windows;

using Prism.Mvvm;
using Newtonsoft.Json;

// https://coinmarketcap.com/
// https://coinmarketcap.com/api/
// https://pro.coinmarketcap.com/account
// https://coinmarketcap.com/api/documentation/v1/#section/Quick-Start-Guide

namespace CryptoSentiment
{
    #region Models
    public class ResponseStatus
    {
        public DateTime timestamp;
        public int error_code;
        public string error_message;
        public int elapsed;
        public int credit_count;
        public string notice;
    }

    public class Platform
    {
        public int id;
        public string name;
        public string symbol;
        public string slug;
        public string token_address;
    }

    public class QuoteData
    {
        public double price;
        public double volume_24h;
        public double percent_change_1h;
        public double percent_change_24h;
        public double percent_change_7d;
        public double percent_change_30d;
        public double percent_change_60d;
        public double percent_change_90d;
        public double market_cap;
        public double market_cap_dominance;
        public double fully_diluted_market_cap;
        public DateTime last_updated;
    }

    public class LatestQuoteResp
    {
        public int id;
        public string name;
        public string symbol;
        public string slug;
        public int num_market_pairs;
        public DateTime date_added;
        // tags
        public double? max_supply;
        public double? circulating_supply;
        public double? total_supply;
        public Platform platform;
        public int is_active;
        public int cmc_rank;
        public DateTime last_updated;
        public Dictionary<string, QuoteData> quote = new Dictionary<string, QuoteData>();
    }

    public class LatestQuoteAsyncResponse
    {
        public ResponseStatus status;
        public Dictionary<string, LatestQuoteResp> data = new Dictionary<string, LatestQuoteResp>();
    }

    public class DataGridQuoteData : BindableBase
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { SetProperty(ref name, value); }
        }

        private string longName;
        public string LongName
        {
            get { return longName; }
            set { SetProperty(ref longName, value); }
        }

        private double price;
        public double Price
        {
            get { return price; }
            set { SetProperty(ref price, value); }
        }

        private double marketCap;
        public double MarketCap
        {
            get { return marketCap; }
            set { SetProperty(ref marketCap, value); }
        }

        private double percentShare;
        public double PercentShare
        {
            get { return percentShare; }
            set { SetProperty(ref percentShare, value); }
        }

        private double volumn24h;
        public double Volumn24h
        {
            get { return volumn24h; }
            set { SetProperty(ref volumn24h, value); }
        }

        private double accumulativeMarketCap;
        public double AccumulativeMarketCap
        {
            get { return accumulativeMarketCap; }
            set { SetProperty(ref accumulativeMarketCap, value); }
        }
    }

    #endregion

    public partial class StableCoin : CrytoUserControl
    {
        private static readonly Lazy<StableCoin> lazy = new Lazy<StableCoin>(() => new StableCoin());

        public static StableCoin Instance { get { return lazy.Value; } }

        private readonly string CoinMarketCapApiKey = "31941fbb-01b9-4bad-bd52-d5aa9d875792";
        private UriBuilder url = null;
        private WebClient client = null;

        public ObservableCollection<DataGridQuoteData> DataGridQuoteData = new ObservableCollection<DataGridQuoteData>();

        public StableCoin()
        {
            InitializeComponent();
            DataContext = this;

            LoadStableCoinMarketShare();
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        { }

        public override void OnInitChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            DataGridQuoteData.Clear();
            LoadStableCoinMarketShare();
        }

        // public static void Sort<T>(this ObservableCollection<T> collection, Comparison<T> comparison)
        public void Sort<T>(ObservableCollection<T> collection, Comparison<T> comparison)
        {
            var sortableList = new List<T>(collection);
            sortableList.Sort(comparison);

            for (int i = 0; i < sortableList.Count; i++)
            {
                collection.Move(collection.IndexOf(sortableList[i]), i);
            }
        }

        // Binds data to properties in XAML
        private void CalculateLatestStableCoinMarketShare(LatestQuoteAsyncResponse resp)
        {
            var data = resp.data;
            double totalmc = 0.0;

            // populate our observable collection
            foreach (var d in data)
            {
                var dg = new DataGridQuoteData();
                dg.Name = d.Key;
                dg.LongName = d.Value.name;

                var qd = new QuoteData();
                d.Value.quote.TryGetValue("USD", out qd);
                dg.MarketCap = qd.market_cap;
                dg.Price = qd.price;
                dg.Volumn24h = qd.volume_24h;

                totalmc += dg.MarketCap;
                dg.AccumulativeMarketCap = totalmc;

                DataGridQuoteData.Add(dg);
            }

            // calculate percent share
            foreach (var dg in DataGridQuoteData) {
                dg.PercentShare = dg.MarketCap / totalmc;
            }

            // update bindable sources
            Sort(DataGridQuoteData, (a, b) => { return a.Name.CompareTo(b.Name); });
            dgStableCoin.ItemsSource = DataGridQuoteData;
        }

        // Testing list
        private void LoadTestStableCoinMarketShare()
        {
            Dictionary<string, LatestQuoteResp> data = new Dictionary<string, LatestQuoteResp>();

            data.Add("USDC", new LatestQuoteResp
            {
                name = "USDC",
                quote = new Dictionary<string, QuoteData> {
                { "USD", new QuoteData { market_cap = 5000.0 } }
            }
            });

            data.Add("DAI", new LatestQuoteResp
            {
                name = "DAI MONEY",
                quote = new Dictionary<string, QuoteData> {
                { "USD", new QuoteData { market_cap = 205.4 } }
            }
            });

            data.Add("USDT", new LatestQuoteResp
            {
                name = "Tether",
                quote = new Dictionary<string, QuoteData> {
                { "USD", new QuoteData { market_cap = 10000.0 } }
            }
            });

            LatestQuoteAsyncResponse resp = new LatestQuoteAsyncResponse() { data = data };
            CalculateLatestStableCoinMarketShare(resp);
        }

        // The real stable coin list
        private void LoadStableCoinMarketShare()
        {
            url = new UriBuilder("https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest");
            var queryString = HttpUtility.ParseQueryString(string.Empty);
            queryString["symbol"] = "PAX,UST,DAI,GUSD,TUSD,BUSD,USDC,USDT";
            url.Query = queryString.ToString();

            client = new WebClient();
            client.Headers.Add("X-CMC_PRO_API_KEY", CoinMarketCapApiKey);
            client.Headers.Add("Accepts", "application/json");

            var json = client.DownloadString(url.ToString());
            var resp = JsonConvert.DeserializeObject<LatestQuoteAsyncResponse>(json);
            CalculateLatestStableCoinMarketShare(resp);
        }
    }
}

////////////////////////////              XAML CODE            ///////////////////////////////////////
/**
<local:CrytoUserControl x:Class="CryptoSentiment.StableCoin"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:CryptoSentiment"
             mc:Ignorable="d" Loaded="OnLoaded">

    <UserControl.Resources>
        <Style x:Key="DataGridStyle1" TargetType="DataGrid">
            <Setter Property="ColumnHeaderStyle" Value="{DynamicResource ColumnHeaderStyle}"/>
        </Style>

        <Style x:Key="CellAlignRight">
            <Setter Property="Control.HorizontalAlignment" Value="Right" />
        </Style>

        <Style x:Key="ColumnHeaderStyle" TargetType="DataGridColumnHeader">
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
        </Style>

        <Style x:Key="DataGridCellStyle" TargetType="DataGridCell">
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="LightSteelBlue" />
                    <Setter Property="BorderThickness" Value="0" />
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style x:Key="DataGridRowStyle" TargetType="DataGridRow">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="Lavender" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>

    <DataGrid x:Name="dgStableCoin" 
              AutoGenerateColumns="False" FontSize="18" 
              CellStyle="{StaticResource DataGridCellStyle}"
              RowStyle="{StaticResource DataGridRowStyle}"
              ColumnHeaderStyle="{StaticResource ColumnHeaderStyle}"              
              AlternatingRowBackground="LightCyan">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Stable Coin" Binding="{Binding Name}" Foreground="Blue" Width="150" />
            <DataGridTextColumn Header="Coin Name" Binding="{Binding LongName}" Foreground="DarkSlateGray" Width="200" />
            <DataGridTextColumn Header="Price" Binding="{Binding Price, StringFormat=N2}" Foreground="Sienna" Width="100" />
            <DataGridTextColumn Header="Market Cap" Binding="{Binding MarketCap, StringFormat=N2}" 
                                Foreground="Purple" Width="300" ElementStyle="{StaticResource CellAlignRight}" />
            <DataGridTextColumn Header="Percent Share" Binding="{Binding PercentShare, StringFormat=P2}" 
                                Foreground="Red" Width="200" ElementStyle="{StaticResource CellAlignRight}" />
            <DataGridTextColumn Header="Volumn 24H" Binding="{Binding Volumn24h, StringFormat=N2}" 
                                Foreground="Chocolate" Width="300" ElementStyle="{StaticResource CellAlignRight}" />
            <DataGridTextColumn Header="Accumulative Market Cap" Binding="{Binding AccumulativeMarketCap, StringFormat=N2}" 
                                Foreground="Magenta" Width="300" ElementStyle="{StaticResource CellAlignRight}" />
        </DataGrid.Columns>
    </DataGrid>
</local:CrytoUserControl>
*/