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 Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Hncore.Pass.Vpn.Service
{
    //金桥
    public class AgentClient4Service: AgentClient1Service
    {
        string LoginUrl { get; set; } = "main/agentLogin.html";
        string LoginCodeUrl { get; set; } = "main/imgcode.html";
        string RefrushTokenUrl { get; set; } = "agent.html";
        string SingleAddUrl { get; set; } = "agent/memberSingleAdd.html";
        string SingleReAddUrl { get; set; } = "agent/memberRenew.html";
        string MuiltAddUrl { get; set; } = "agent/memberMuiltAdd.html";
        string RefundUrl { get; set; } = "agent/memberRefundAct.html ";      
        string UpdateUrl = "agent/memberUpdate/id/";//agent/memberUpdate/id/1155709.html 
        string OnlineUrl { get; set; } = "";
        string KIllUrl { get; set; } = "";
        string searchAccountUrl = "agent/memberList/type/1.html?search=1&username=";
        string searchTestAccountUrl = "agent/memberList/type/0.html?search=1&username=";
        string DeleteUrl { get; set; } = "agent/memberDel/id/";//1160862.html";
        string KillUrlClient = "/agent/disConnect/sessionid/{0}.html";
        string ClientOnlineUrl { get; set; } = "agent/clientOnline/page/{0}.html";
        IHttpClientFactory m_HttpClientFactory;       
        public AgentClient4Service(IHttpClientFactory httpClientFactory):base(httpClientFactory)
        {
            m_HttpClientFactory = httpClientFactory;
        } 

        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);
                    var content = await getResp.Content.ReadAsStringAsync();
                    if (getResp.StatusCode == HttpStatusCode.OK && content.IndexOf("agentLogin.html") == -1)
                    {
                        status = 1;
                    }
                    else
                    {                     
                        Debug.WriteLine("离线");
                        Debug.WriteLine(content);
                    }
                }
            }
            return status;
        }
        public override async Task<(byte[], string)> GetCode()
        {          
            var client = CreateHttpClient(false);
            if (this.LoginUrl.NotHas()) return (null, "");  
            var getResp = await client.GetAsync(this.LoginUrl);
            var cookie = this.GetCookie(getResp, "PHPSESSID");
            if (cookie.Has())
            {
                client.DefaultRequestHeaders.Add("Cookie", cookie);
                var ret = await client.GetByteArrayAsync(this.LoginCodeUrl + "?t=" + DateTime.Now.Millisecond);
                return (ret, cookie);
            }
            return (null, "");
        }
        public override async Task<ApiResult> Login(AgentLoginRequest request)
        {
            var client = CreateHttpClient(false);

            var map = new Dictionary<string, string>(){
                {"agentName",request.Account },
                {"password",request.Pwd },
                {"authnum",request.Code },
            };
            LogHelper.Info("Login", map.ToJson());
            AddCookie(client, request.Key);
            //client.DefaultRequestHeaders.Add("Cookie", request.Key);
            var resp = await client.PostAsForm(this.LoginUrl, map);
            var content = await resp.Content.ReadAsStringAsync();
            if (content.IndexOf("alert alert-danger") != -1)
            {
                return new ApiResult(ResultCode.C_VISITOR_CHECKING, "登录失败");
            }           
            return new ApiResult(request.Key);
        }
        public override bool CheckAccount(int productId,List<string> accounts)
        {
            return false;
        }

        /// <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 client = CreateHttpClient();
            var map = new Dictionary<string, string>(){
                {"taocanName",packageKey },
                {"username",account },
                {"password",pwd },
                {"maxonline",connCount.ToString()},
                {"type",accountType.ToString()}
            };
            var title = GetOpTitle("NewAccount", account);
            LogHelper.Info(title, map.ToJson());
            try
            {
                var resp = await client.PostAsForm(this.SingleAddUrl, map);
                var content = await resp.Content.ReadAsStringAsync();
                if (content.Has() && content.IndexOf("{alert(\"成功\")") != -1)
                {
                    return new ApiResult(ResultCode.C_SUCCESS);
                }
                else
                {
                    LogHelper.Error(title, content);
                    return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message);
                return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
            }
        }

        /// <summary>
        /// 新开
        /// </summary>
        /// <param name="packageId"></param>
        /// <param name="account"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public override async Task<ApiResult> NewMuiltAccount(string packageKey, string account, string pwd, int connCount = 1, int accountType = 1,int startNum=0, int endNum=1 )
        {
            var client = CreateHttpClient();
            var map = new Dictionary<string, string>(){
                {"taocanName",packageKey },
                {"usernameTpl",account },
                {"password",pwd },
                {"maxonline",connCount.ToString()},
                {"startNum",startNum.ToString()},
                {"endNum",endNum.ToString()},
                {"mode",accountType.ToString()},
            };
            var title = GetOpTitle("NewMuiltAccount", account);
            LogHelper.Info(title, map.ToJson());
            try
            {
                var resp = await client.PostAsForm(this.MuiltAddUrl, map);
                var content = await resp.Content.ReadAsStringAsync();
                if (content.Has() && content.IndexOf("<td>成功</td>") != -1)
                {
                    return new ApiResult(1);
                }
                else
                {
                    LogHelper.Error(title, content);                  
                    return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message);
                return new ApiResult(ResultCode.C_INVALID_ERROR, "开户失败");
            }       
        }

        /// <summary>
        /// 续费
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public override async Task<ApiResult> NewReAccount(string packageKey, string account, int connCount, int payCount = 1)
        {
            var client = CreateHttpClient();
            var map = new Dictionary<string, string>(){
                {"taocanName",packageKey },
                {"username",account },
                {"iscz","3" },
            };
            var title = GetOpTitle("NewReAccount", account);
            LogHelper.Info(title, map.ToJson());
            try
            {
                var resp = await client.PostAsForm(this.SingleReAddUrl, map);
                var content = await resp.Content.ReadAsStringAsync();
                if (content.Has() && content.IndexOf("alert(\"成功\")") != -1)
                {
                    return new ApiResult(1);
                }
                else
                {
                    LogHelper.Error(title, content);
                    return new ApiResult(ResultCode.C_INVALID_ERROR, "续费失败");
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message);
                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 infoRet = await this.GetAccountInfo(account, true);
            if (infoRet.Code != ResultCode.C_SUCCESS)
                return false;

            var title = GetOpTitle("DeleteAccount", account);
            LogHelper.Info(title, account);
            try
            {
                var delete = this.DeleteUrl + infoRet.Data.Id + ".html";
                var resp = await client.GetAsync(delete);
                var content = await resp.Content.ReadAsStringAsync();
                if (content.Has() && content.IndexOf("alert(\"删除成功\")") != -1)
                {
                    return true;
                }
                else
                {
                    LogHelper.Error(title, content);
                    return false;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message);
                return false;
            }
        }
        /// <summary>
        /// 得到账号信息
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public override async Task<ApiResult<OriginAccountModel>> GetAccountInfo(string account,bool isTest=false)
        {
            var client = CreateHttpClient();           
            var title = GetOpTitle("GetAccountInfo", account);
            var info = "";
            try
            {
                var url = this.searchAccountUrl + account;
                if (isTest)
                {
                    url = this.searchTestAccountUrl + account;
                }
                var resp = await client.GetAsync(url);
                var content = await resp.Content.ReadAsStringAsync();

                var parser = new HtmlParser();
                var document = await parser.ParseDocumentAsync(content);
                ////table class="table table-bordered"
                var trs = document.QuerySelectorAll("table.table tr").ToList();
                // var trs= table.QuerySelectorAll("tr").ToList();
                var retData = new List<OriginAccountModel>();
                if (trs.Count() > 1)
                {
                   //var  tr = trs.Skip(1).FirstOrDefault();
                    foreach(var tr in trs.Skip(1))
                    {
                        var tds = tr.QuerySelectorAll("td").ToList();                   
                        var tdAccount = tds[1].FirstChild.TextContent;
                        if (tdAccount != account)
                            continue;
                        info = string.Join("", tds.Select(m => m.OuterHtml)); 
                        //<td >会员账号</td><td >类型</td><td >套餐</td><td >注册日期 过期日期</td><td>专线IP  </td><td >连接数</td><td >余额</td><td >激活</td><td >备注</td>

                        var dateText = tds[4].InnerHtml;
                        var endtext = dateText.Split("<br>")[1].Split('\n');
                        var trData = new OriginAccountModel
                        {
                            Account = account,
                            Pwd = tds[1].QuerySelector("font").TextContent,
                            AccountType = tds[2].TextContent,
                            Package = tds[3].TextContent,
                            RegistTime = dateText.Split("<br>")[0],
                            EndTime = endtext[0].Replace("\n", "").Replace("\t", ""),
                            RestTime = endtext[1].Replace("\n", "").Replace("\t", ""),
                            ConnectCount = tds[6].TextContent,
                            Amount = tds[7].TextContent,
                            IsActive = tds[8].TextContent,
                            Remark = tds[9].TextContent,
                        };

                        trData.RealEndTime = DateTime.Parse(trData.EndTime);
                        if (trData.RestTime.Contains("已过期"))
                        {
                            trData.RestTime = "已过期";
                        }else
                        {
                            // "6.14:32"
                            var timeStr = trData.RestTime.Replace("天", ".").Replace("时", ":").Replace("分", "");
                            var restTime = TimeSpan.Parse(timeStr);
                            trData.RealEndTime = DateTime.Now.Add(restTime);
                        }

                        var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
                        if (href.Has())
                        {
                            var start = href.LastIndexOf('/');
                            var end = href.IndexOf(".html");
                            if (start != -1 && end != -1)
                            {
                                trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
                            }
                        }
                        return new ApiResult<OriginAccountModel>(trData);
                    }
                   
                }           
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message+"-->info:"+ info);
                return new ApiResult<OriginAccountModel>(ResultCode.C_INVALID_ERROR, "查询失败");
            }

            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 ret = await this.GetAccountInfo(account);
            if (ret.Code != ResultCode.C_SUCCESS)
            {
                return false;
            }
            var accountModel = ret.Data;            
            if (accountModel == null)
            {
                return false;
            }
            var client = CreateHttpClient();
            var map = new Dictionary<string, string>(){
                   {"username",account },
                   {"password",pwd },
                   {"submit","提交" },
            };
            LogHelper.Info(GetOpTitle("UpdateAccountPwd", account), map.ToJson());
            try
            {
                var resp = await client.PostAsForm(this.UpdateUrl + accountModel.Id + ".html", map);
                var content = await resp.Content.ReadAsStringAsync();
                if (content.Has() && content.IndexOf("更新成功") != -1)
                {
                    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 account, string packageKey, int days)
        {
            var client = CreateHttpClient();
            var map = new Dictionary<string, string>(){
                {"refundUser",account },
                {"refundReason","hl" },              
            };
            var title = GetOpTitle("Refund", account);
            LogHelper.Info(title, map.ToJson());
            try
            {
                var resp = await client.PostAsForm(this.RefundUrl, map);
                var content = await resp.Content.ReadAsStringAsync();
                if (content.Has() && content.IndexOf("alert(\"退款成功\")") != -1)
                {
                    return new ApiResult(1);
                }
                else
                {
                    LogHelper.Error(title, content);
                    return new ApiResult(ResultCode.C_INVALID_ERROR, "退款失败");
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message);
                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 onlines = await base.OnLine(account);

            if (onlines.Code == ResultCode.C_SUCCESS && onlines.Data.Count > 0)
                return onlines;
            var retData = new List<OriginAccountOnlineModel>();
            var client = CreateHttpClient();
            int page = 1;
            var url = string.Format(this.ClientOnlineUrl, page);
            var resp = await client.GetAsync(url);
            var content = await resp.Content.ReadAsStringAsync();

            var parser = new HtmlParser();
            var document = await parser.ParseDocumentAsync(content);
            var table = document.QuerySelectorAll("table");
            var pageP = table?.Next("p")?.FirstOrDefault();
            if (pageP != null)
            {
                var total = 0;
                if (pageP.TextContent.Has())
                {
                    var start = pageP.TextContent.IndexOf('(');
                    var end = pageP.TextContent.IndexOf("页)");
                    var pageStr = pageP.TextContent.Substring(start + 2, end - start - 1);
                    int.TryParse(pageStr, out total);
                }
                if (total > 1)
                {
                    await Enumerable.Range(1, total).ForEachAsync(async (int i) =>
                    {
                        var ret = await ClientOnLine(account, i);
                        retData.AddRange(ret);
                    });
                }
                else
                {
                    retData = await ClientOnLine(account, 1);
                }
            }
            else
            {
                retData = await ClientOnLine(account, 1);
            }
            return new ApiResult<List<OriginAccountOnlineModel>>(retData);
        }

        public  async Task<List<OriginAccountOnlineModel>> ClientOnLine(string account,int page=1)
        {        
            var client = CreateHttpClient();
            var title = GetOpTitle("ClientOnLine", account);
            var info = "";
            var retData = new List<OriginAccountOnlineModel>();
            try
            {
                var url =string.Format(this.ClientOnlineUrl,page);
                var resp = await client.GetAsync(url);
                var content = await resp.Content.ReadAsStringAsync();
                var parser = new HtmlParser();
                var document = await parser.ParseDocumentAsync(content);
                var trs = document.QuerySelectorAll("table.table tr").ToList();
              
                if (trs.Count() > 1)
                {
                    foreach (var tr in trs.Skip(1))
                    {
                        var tds = tr.QuerySelectorAll("td").ToList();
                        var tdAccount = tds[1].FirstChild.TextContent;
                        if (tdAccount != account)
                            continue;
                        info = string.Join("", tds.Select(m => m.OuterHtml));
                        //序号	会员账号	登录时间	在线时长	客户端IP地址	操作
                        var trData = new OriginAccountOnlineModel
                        {
                            Account = account,
                            LoginTime = tds[2].TextContent,
                            OnlineTime = tds[3].TextContent,
                            LoginIP = tds[4].TextContent,                        
                        };
                        var href = tr.LastElementChild.QuerySelector("a")?.Attributes["href"]?.Value;
                        if (href.Has())
                        {
                            var start = href.LastIndexOf('/');
                            var end = href.IndexOf(".html");
                            if (start != -1 && end != -1)
                            {
                                trData.Id = href.Substring(start + 1, end - start).TrimEnd('.');
                            }
                        }
                        retData.Add(trData);
                    }
                }
                return retData;
            }
            catch (Exception ex)
            {
                LogHelper.Error(title, ex.Message + "-->info:" + info);             
            }
            return retData;        
        }

        /// <summary>
        /// 踢号
        /// </summary>
        /// <param name="productId"></param>
        /// <param name="account"></param>
        /// <returns></returns>
        public override async Task<bool> KillOut( string id)
        {
            var flag = await base.KillOut(id);
            if (flag) return true;

            var client = CreateHttpClient();
            var title = GetOpTitle("KillOut", id);
            var info = "";
            try
            {
                var url = string.Format(this.KillUrlClient, id);
                var resp = await client.GetAsync(url);
                var content = await resp.Content.ReadAsStringAsync();
                if (content.Has() && content.IndexOf("已经向客户端发送断开消息") != -1)
                {
                    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 title = GetOpTitle("Exist", account);
            LogHelper.Info(title, account);
            var testRet = await this.NewAccount("free", account, "1234", 1, 0);
            if (testRet.Code == ResultCode.C_SUCCESS)
            {
                await DeleteAccount(account);
                return false;
            }              
            return true;
        }
    }
}
