using AngleSharp;
using AngleSharp.Dom;
using AngleSharp.Html.Parser;
using Hncore.Infrastructure.Common;
using Hncore.Infrastructure.Extension;
using Hncore.Infrastructure.Serializer;
using Hncore.Infrastructure.WebApi;
using Hncore.Pass.Vpn.Model;
using Hncore.Pass.Vpn.Request.Product;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
    public class AgentClient7Service : AgentClientBaseService
    {
        string apiId = "89";
        string apiKey = "NFeK72yYXmPiGR86YeMCBRTWDxXkrQsd";
        string LoginIndexUrl { get; set; } = "login";
        string LoginUrl { get; set; } = "login";
        string LoginCodeUrl { get; set; } = "";
        string RefrushTokenUrl { get; set; } = "my";
        string SingleAddUrl { get; set; } = "api/add";
        string SingleReAddUrl { get; set; } = "v1/renewal";
        string MuiltAddUrl { get; set; } = "agent/memberMuiltAdd.html";
        string RefundUrl { get; set; } = "agent/memberRefundAct.html ";
        string UpdateUrl = "v1/edit";
        string OnlineLoginUrl { get; set; } = "online";
        string OnlineUrl { get; set; } = "v1/oln";
        string KIllUrl { get; set; } = "agent/disConnect2/radacctid/{0}.html";
        string searchAccountUrl = "v1/get";
        string DeleteUrl { get; set; } = "v1/refund";//1160862.html";

        string ExistUrl = "v1/verify";
        IHttpClientFactory m_HttpClientFactory;
        public AgentClient7Service(IHttpClientFactory httpClientFactory) : base(httpClientFactory)
        {
            m_HttpClientFactory = httpClientFactory;
        }

        protected override HttpClient CreateHttpClient(bool autoCooke = true)
        {
            var client = m_HttpClientFactory.CreateClient("agentClient1.0");
            client.BaseAddress = new System.Uri(this.BaseUrl);
            if (this.Token.Has() && autoCooke)
            {
                AddCookie(client, this.Token);
            }
            return client;
        }

        public override async Task<int> RefrushStatus()
        {
            int status = 0;
            if (this.Token.Has())
            {
                var client = CreateHttpClient();
                if (this.RefrushTokenUrl.Has())
                {
                    // client.DefaultRequestHeaders.Add("Cookie", this.Token);
                    var getResp = await client.GetAsync(this.RefrushTokenUrl);
                    if (getResp.StatusCode == HttpStatusCode.OK)
                    {
                        status = 1;
                    }
                    else
                    {
                        var request = new AgentLoginRequest()
                        {
                            Account = this.Product.Account,
                            Pwd = this.Product.Pwd
                        };

                        var ret = await this.Login(request);
                        if (ret.Code == ResultCode.C_SUCCESS)
                        {
                            this.Product.Token = ret.Data.ToString();
                            status = 1;
                        }
                        else
                        {
                            Debug.WriteLine("离线");
                        }                      
                    }
                }
            }
            return status;
        }

        private async Task<(string, string)> GetHomeCookie()
        {
            var client = CreateHttpClient(false);
            client.BaseAddress = new Url("https://yoyoapi.yoyoip.com/");
            var getResp = await client.GetAsync(this.LoginIndexUrl);
            var cookies = this.GetCookies(getResp);
            cookies = cookies.Replace("path=/;", "").Replace("httponly", "").Trim();

            var content = await getResp.Content.ReadAsStringAsync();

            var parser = new HtmlParser();
            var document = await parser.ParseDocumentAsync(content);
            var csrf_tokenNode = document.QuerySelector("meta[name=csrf-token]");//<meta name="csrf-token" content="WfjPwY-RY_A_3d09abknzQm-eRDaVnDeMNRxN-juDDEYzomD3cshgk-zk3M94FC9P8Yte6AjCvMCmz4BmYZvSw==">
            var csrf_token = csrf_tokenNode.GetAttribute("content");
            return (cookies, csrf_token);
        }

        public override async Task<ApiResult> Login(AgentLoginRequest request)
        {
            var tokens = await this.GetHomeCookie();            
            var client = CreateHttpClient(false);
            client.BaseAddress = new Url("https://yoyoapi.yoyoip.com");
            client.DefaultRequestHeaders.Add("Connection", "keep-alive");
            client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
            var map = new Dictionary<string, string>(){
                {"_csrf-daili",tokens.Item2},
                {"LoginForm[username]",request.Account },
                {"LoginForm[password]",request.Pwd },
            };
            LogHelper.Info("Login", map.ToJson());

            var csrf = GetCookieValue(tokens.Item1, "_csrf-daili");
            AddCookie(client, $"_csrf-daili={csrf}");
            var resp = await client.PostAsForm(this.LoginUrl, map);
            var content = await resp.Content.ReadAsStringAsync();
            if (resp.StatusCode != HttpStatusCode.OK || content.IndexOf("成功") == -1)
            {
                return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败");
            }
            var frontend = this.GetCookie(resp, "advanced-frontend");
            csrf = this.GetCookie(resp, "_csrf-daili");
            request.Key = $"{frontend};{csrf}";
            return new ApiResult(request.Key);
        }
        public override bool CheckAccount(int productId,List<string> accounts)
        {
            return false;
        }


        private string Sign(SortedDictionary<string, string> map)
        {
            map["apiid"] = this.apiId;
            map["sendtime"] = DateTime.Now.GetUnixTimeStamp().ToString();
            var data = string.Join("&", map.Select(m => $"{m.Key}={m.Value}"));
            var signStr = Md5(data + apiKey);
            data = $"{data}&sign={signStr}";
            return data;
        }

        //Md5摘要
        private static string Md5(string text)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] fromData = System.Text.Encoding.UTF8.GetBytes(text);
            byte[] targetData = md5.ComputeHash(fromData);
            string byte2String = null;

            for (int i = 0; i < targetData.Length; i++)
            {
                byte2String += targetData[i].ToString("x2");
            }

            return byte2String;
        }

        /// <summary>
        /// 新开
        /// </summary>
        /// <param name="packageId"></param>
        /// <param name="account"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public override async Task<ApiResult> NewAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1, int payCount = 1)
        {
            var new_url = "v1/one";
            var client = CreateHttpClient();   
            var package = "m";       
            var buyCount = "1";       
            if(packageKey =="test"){
                new_url = "v1/test";
            } else if(packageKey =="m3"){
                package = "m";
                buyCount = "3";
            } else if(packageKey =="m12"){
                package = "m";
                buyCount = "12";
            } else {
                package = packageKey;
                buyCount = payCount.ToString();
            }
            var map = new SortedDictionary<string, string>(){
                {"name",account },
                {"passwd",pwd },
                {"num","1"},
                {"max_conn",connCount.ToString() },
                {"paytype",package },
                {"paynum",buyCount },
                {"product_id",accountType.ToString() },
                {"mobile","13073735878" },
                {"mark","api" },
            };
            var title = GetOpTitle("NewAccount", account);
            try
            {               
                var resp = await client.GetAsync(new_url+"?"+ Sign(map));
                var content = await resp.Content.ReadAsStringAsync();
                JObject jo = (JObject)JsonConvert.DeserializeObject(content);
                var status = jo["status"].ToString();
                if (status =="200")
                {
                    var retAccount=jo["data"].ToArray().FirstOrDefault();
                    // var id = retAccount["name"].ToString();
                    return new ApiResult(ResultCode.C_SUCCESS);
                }
                else
                {
                    var info = jo["info"].ToString();
                    LogHelper.Error(title, content);
                    return new ApiResult(ResultCode.C_INVALID_ERROR, info);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message);
                return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
            }
        }

        /// <summary>
        /// 续费
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account">原始的账号的id</param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public override async Task<ApiResult> NewReAccount(string packageKey, string id, int connCount, int payCount = 1)
        {
            var package = "m";       
            var buyCount = "1";       
            if(packageKey =="m3"){
                package = "m";
                buyCount = "3";
            } else if(packageKey =="m12"){
                package = "m";
                buyCount = "12";
            } else {
                package = packageKey;
                buyCount = payCount.ToString();
            }         
            var client = CreateHttpClient();
            var map = new SortedDictionary<string, string>(){
                {"names",id },      //原始的账号的id
                {"paytype",package },
                {"paynum",buyCount },
            };

            try
            {
                var resp = await client.GetAsync(this.SingleReAddUrl + "?" + Sign(map));              
                var content = await resp.Content.ReadAsStringAsync();
                JObject jo = (JObject)JsonConvert.DeserializeObject(content);
                var status = jo["status"].ToString();
                if (status =="200")
                {
                    return new ApiResult(ResultCode.C_SUCCESS);
                }
                else
                {
                    var info = jo["info"].ToString();
                    return new ApiResult(ResultCode.C_INVALID_ERROR, info);
                }
            }
            catch (Exception ex)
            {
                return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
            }
        }
        /// <summary>
        /// 删除账号
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public override async Task<bool> DeleteAccount(string account)
        {
            var client = CreateHttpClient();
            var map = new SortedDictionary<string, string>(){
                {"name",account },
            };

            try
            {               
                var resp = await client.GetAsync(this.DeleteUrl + "?" + Sign(map));
                var content = await resp.Content.ReadAsStringAsync();
                JObject jo = (JObject)JsonConvert.DeserializeObject(content);
                var status = jo["status"].ToString();
                if (status=="200")
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        /// <summary>
        /// 得到账号信息
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public override async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string id, bool isTest=false)
        {
            var client = CreateHttpClient();
            var map = new SortedDictionary<string, string>(){
                {"name",id },
            };
            try
            {
                var resp = await client.GetAsync(this.searchAccountUrl + "?" + Sign(map));
                var content = await resp.Content.ReadAsStringAsync();
                JObject jo = (JObject)JsonConvert.DeserializeObject(content);
                var status = jo["status"].ToString();

                if (status == "200")
                {
                    var data = jo["data"];
                    var trData = new OriginAccountModel
                    {
                        Id = data["name"].ToString(),
                        Account = data["name"].ToString(),
                        Pwd = data["passwd"].ToString(),
                        AccountType = data["mark"].ToString(),
                        Package = "",
                        ConnectCount = data["max_conn"].ToString(),
                        RegistTime = data["add_time"].ToString(),
                        EndTime = data["end_time"].ToString(),
                        RestTime = "",
                        Amount = data["balance"].ToString(),
                        Remark = data["mark"].ToString(),
                    };
                    return new ApiResult<OriginAccountModel>(trData);
                }
                else
                {
                    var info = jo["info"].ToString();
                    return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "没有查询到信息");
                }
            }
            catch (Exception ex)
            {
                return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "查询失败");
            }

        }
        /// <summary>
        /// 修改账号密码
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public override async Task<bool> UpdateAccountPwd(string account, string pwd)
        {
            var client = CreateHttpClient();
            var map = new SortedDictionary<string, string>(){
                {"name",account },
                {"passwd",pwd },
            };
            try
            {
                var resp = await client.GetAsync(this.UpdateUrl + "?" + Sign(map));
                var content = await resp.Content.ReadAsStringAsync();
                JObject jo = (JObject)JsonConvert.DeserializeObject(content);
                var status = jo["status"].ToString();
                if (status == "200")
                {
                    return true;
                }
                else
                {
                    LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), content);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(GetOpTitle("UpdateAccountPwd", account), ex);
            }
            return false;
        }
        /// <summary>
        /// 退款
        /// </summary>
        /// <param name="packageId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public override async Task<ApiResult> Refund(string id, string packageKey, int days)
        {
            var ret = await this.DeleteAccount(id);
            if (ret)
            {
                return new ApiResult(ResultCode.C_SUCCESS);
            }
            else
            {
                return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
            }
        }
        /// <summary>
        /// 是否在线
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public override async Task<ApiResult<List<OriginAccountOnlineModel>>> OnLine(string account)
        {         
            var client = CreateHttpClient();
            var map = new SortedDictionary<string, string>(){
                {"name",account },
            };

            var resp = await client.GetAsync(this.OnlineUrl + "?" + Sign(map));
            var content = await resp.Content.ReadAsStringAsync();
            JObject jo = (JObject)JsonConvert.DeserializeObject(content);

            var status = jo["status"].ToString();
            var retData = new List<OriginAccountOnlineModel>();
            if (status =="200")
            {
                if(jo["data"]["total"].ToInt()>0){
                    foreach (var tr in jo["data"]["items"])
                    {
                        JObject jsondata = (JObject)JsonConvert.DeserializeObject(tr.ToJson());

                        var trData = new OriginAccountOnlineModel
                        {
                            Account = account,
                            ServerIP = jsondata["ip"].ToString(),
                            LoginTime = "",
                            OnlineTime = "",
                            LoginIP = jsondata["user_ip"].ToString(),
                            UpStream = "",
                            DownStream = "",
                            Id=  jsondata["id"].ToString(),
                        
                        };
                        
                        retData.Add(trData);
                    }
                }
                return new ApiResult<List<OriginAccountOnlineModel>>(retData);
            }
            else
            {
                 return new ApiResult<List<OriginAccountOnlineModel>>(ResultCode.C_INVALID_ERROR, "查询失败");
            }
        }
        /// <summary>
        /// 踢号
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public override async Task<bool> KillOut( string id)
        {
            var client = CreateHttpClient();
            var title = GetOpTitle("KillOut", id);
            var info = "";
            var map = new SortedDictionary<string, string>(){
                {"id",id },
            };
            try
            {
                var resp = await client.GetAsync("v1/olnstop?" + Sign(map));
                var content = await resp.Content.ReadAsStringAsync();
                return true;                         
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message + "-->info:" + info);              
            }
            return false;
        }

        /// <summary>
        /// 是否存在
        /// </summary>      
        /// <param name="account"></param>
        /// <returns></returns>
        public override async Task<bool> Exist(string account)
        {
            var client = CreateHttpClient();

            var map = new SortedDictionary<string, string>(){               
                {"user",account }           
            };
            var title = GetOpTitle("Exist", account);
            LogHelper.Info(title, account);
            try
            {
                var resp = await client.GetAsync(this.ExistUrl + "?" + Sign(map));
                var content = await resp.Content.ReadAsStringAsync();
                JObject jo = (JObject)JsonConvert.DeserializeObject(content);
                var status = jo["status"].ToString();
                if (status != "200")
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex);
            }
            return false;
        }
    }
}
