//using Cex.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Text;
using WebSocket.Interfaces;
using System.Linq;
using System.Threading.Tasks;
using System.Globalization;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Linq;
using System.IO;
using Bittrex.Net.Objects;

namespace WebSocket.Clients
{
    public class BittrexWebClient : IWebClient
    {
        #region Members
        private Dictionary<string, Action<Command, string>> CommandAnswers = new Dictionary<string, Action<Command, string>>();
        private IWebSocketForClient server;
        #endregion

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="server"></param>
        public BittrexWebClient(IWebSocketForClient server)
        {
            this.server = server;
            Register();
        }

        public void Connected()
        {
            //SendAuth();
            //wait connected message?
        }
        
        //private void Update(string name, Command command, string message, Type dataType) {
        //    data[name]= JsonConvert.DeserializeObject(message, dataType, GetSettings());
        //    this.server.updateData.Invoke(this.server.ExchangeId, "Binance", GetMarketOHLCVData());
        //}

        private void Register()
        {
            //On("kline", (c, obj) => Update(((BinanceModel)c).stream, c, obj, typeof(BinanceModel)));
            //On("ping", (c, obj) => SendPong());
        }

        public void Message(string message)
        {
            var parse = JsonConvert.DeserializeObject<BinanceModel>(message, GetSettings());
            if (parse.data != null && CommandAnswers.ContainsKey(parse.data.e))
            {
                CommandAnswers[parse.data.e](parse, message);
            }
        }

        public void Tick()
        {
            //'ticker' or 'get-balance'
        }

        public void Data(byte[] data)
        {
        }

        public void Data(Dictionary<string, object> data)
        {
            //this.server.updateData.Invoke(this.server.ExchangeId, "Bittrex", GetMarketOHLCVData(data));
            this.server.DataChanged("Bittrex", GetMarketOHLCVData(data));
        }

        //private Dictionary<string, IMarketOHLCVData> GetMarketOHLCVData(Dictionary<string, BittrexStreamMarketSummary> data)
        //{
        //    return data.Where(x => x.Value != null).Select(x => new MarketOHLCVData()
        //    {
        //        PairSymbol = x.Value.MarketName,
        //        HighPrice = x.Value.High.Value,
        //        LowPrice = x.Value.Low.Value,
        //        OpenPrice = x.Value.PrevDay.Value,
        //        ClosePrice = x.Value.Last.Value,
        //        Volume = x.Value.Volume.Value,
        //        TimeStamp = x.Value.TimeStamp
        //    } as IMarketOHLCVData).ToDictionary(x => x.PairSymbol);
        //}

        public void Closed(bool byUser, string reason)
        {
            //subscribed = false;
        }

        public void Error(Exception ex)
        {
        }

        public void Error(string reason)
        {
        }

        public void SendFailed(string data, Exception ex)
        {
        }

        private void Send(object obj)
        {
            server.Send(JsonConvert.SerializeObject(obj, GetSettings()));
        }

        private void SendPong()
        {
            Send(new Command() { E = "pong" });
        }

        private void On(string name, Action<Command, string> command)
        {
            CommandAnswers[name] = command;
        }

        private void Off(string name)
        {
            if (CommandAnswers.ContainsKey(name))
            {
                CommandAnswers.Remove(name);
            }
        }

        public Dictionary<string, IMarketOHLCVData> GetMarketOHLCVData(Dictionary<string, object> data)
        {
            return data.Where(x => x.Value != null).Select(x =>
            {
                var item = ((BittrexStreamMarketSummary)x.Value);
                var pairValue = item.MarketName;
                var pair = item.MarketName.Split('-');

                if (pair.Count() == 2) {
                    pairValue = $"{pair[1]}-{pair[0]}";
                }
                return new MarketOHLCVData()
                {
                    PairSymbol = pairValue,
                    HighPrice = item.High.Value,
                    LowPrice = item.Low.Value,
                    OpenPrice = item.PrevDay.Value,
                    ClosePrice = item.Last.Value,
                    Volume = item.Volume.Value,
                    TimeStamp = item.TimeStamp
                } as IMarketOHLCVData;
            }
            ).ToDictionary(x => x.PairSymbol);

            //return data.Select(x => new MarketOHLCVData()
            //{
            //    PairSymbol = ((BinanceModel)x.Value).data.s,
            //    HighPrice = ((BinanceModel)x.Value).data.Data.HighPrice,
            //    LowPrice = ((BinanceModel)x.Value).data.Data.LowPrice,
            //    OpenPrice = ((BinanceModel)x.Value).data.Data.OpenPrice,
            //    ClosePrice = ((BinanceModel)x.Value).data.Data.ClosePrice,
            //    Volume = ((BinanceModel)x.Value).data.Data.Volume,
            //    TimeStamp = ((BinanceModel)x.Value).data.Data.CloseTime
            //} as IMarketOHLCVData).ToDictionary(x => x.PairSymbol);
        }

        private JsonSerializerSettings GetSettings()
        {
            var settings = new JsonSerializerSettings()
            {
                ContractResolver = new LowerCaseUnderscoreContractResolver()
                //Formatting = Formatting.Indented
            };
            //settings.Converters.Add(new MicrosoftSecondsDateTimeConverter()); 
            return settings;
        }
    }
}
