using Grpc.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using XYY.Service.Standard.TrackingService;
using XYY.Core.Standard.Data.Infrastructure;
using Dapper;
using XYY.Data.Model.Standard.Tracking._17;
using Microsoft.Extensions.Caching.Distributed;
using XYY.Common.Standard;
using Newtonsoft.Json;
namespace XYY.gRpc.Tracking
{
    public class SeventeenPushService : SeventeenPush.SeventeenPushBase
    {
        private readonly IUnitOfWork unitOfWork;

        private readonly IDistributedCache dbCache;

        string apiHost = "https://api.17track.net/track/v1";
        string apiKey = "A0F2AC70072D8F1E34209828E4116A26";
        string _17CarriesKey = "@17CarriesCache";
        string _17CarrierUrl = "https://res.17track.net/asset/carrier/info/carrier.all.json";
        List<_17ApiGetCarrierResult> _17Carriers = null;

        public SeventeenPushService(IUnitOfWork unitOfWork, IDistributedCache dbCache)
        {
            this.unitOfWork = unitOfWork;
            this.dbCache = dbCache;
        }

        private async Task<string> GetCarrier(string code)
        {
            if (string.IsNullOrEmpty(code))
                throw new Exception("找不到相关的code");

            if (_17Carriers == null)
            {
                var caches = await dbCache.GetAsync(_17CarriesKey, async () =>
                {
                    System.Net.WebClient client = new System.Net.WebClient();
                    string message = string.Empty;

                    try
                    {
                        string _17ResultStr = await client.DownloadStringTaskAsync(new Uri(_17CarrierUrl));
                        return _17ResultStr;
                    }
                    catch (Exception ex)
                    {
                        throw new Exception($"获取17服务商列表失败，地址:{_17CarrierUrl}" + ex.Message);
                    }

                });
                try
                {
                    List<_17ApiGetCarrierResult> results
                    = JsonConvert.DeserializeObject<List<_17ApiGetCarrierResult>>(caches);
                    if (results.Count == 0)
                    {
                        throw new Exception($"获取Json内容列表为空，地址:{_17CarrierUrl}");
                    }
                    else
                    {
                        _17Carriers = results;
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception($"解析json内容失败，地址:{_17CarrierUrl}" + ex.Message);
                }
            }

            string key = _17Carriers.FirstOrDefault(x => x._name.Equals(code.Replace("-", " "), StringComparison.OrdinalIgnoreCase) ||
                x._name.Equals(code, StringComparison.OrdinalIgnoreCase))?.key;
            if (string.IsNullOrEmpty(key))
            {
                throw new Exception("找不到17服务商" + key);
            }
            return key;
        }
        private async Task<_17PushResult> Push(List<_17ApiPushItem> items)
        {
            System.Net.WebClient client = new System.Net.WebClient();
            client.Headers.Add("17token", apiKey);
            client.Headers.Add("Content-Type", "application/json");
            string data = JsonConvert.SerializeObject(items);
            try
            {
                string mesage = await client.UploadStringTaskAsync(apiHost + "/register", data);
                try
                {
                    var apiResult = JsonConvert.DeserializeObject<_17PushResult>(mesage);
                    if (apiResult.code == 0)
                    {
                        return apiResult;
                    }
                    else
                    {
                        throw new Exception("提交17数据失败-接口返回，请查阅具体错误" +
                             "https://api.17track.net/zh-cn/admin/doc#%E9%94%99%E8%AF%AF%E7%8A%B6%E6%80%81%E7%A0%81" + apiResult.code);
                    }
                }
                catch (Exception ex)
                {
                    throw new Exception("提交17数据-解析消息失败" + ex.Message);
                }
            }
            catch (Exception ex)
            {
                throw new Exception("提交17数据失败-Net/IO Error" + ex.Message);
            }
        }

        public override async Task<PostPushDataResult> PostPushData(GetPushDataResult request, ServerCallContext context)
        {
            List<PostPushDataResultItem> resultData = new List<PostPushDataResultItem>();
            List<_17ApiPushItem> waitUpdateData = new List<_17ApiPushItem>();
            foreach (var item in request.Items)
            {

                try
                {
                    string code = await GetCarrier(item.ServiceCode);
                    waitUpdateData.Add(new _17ApiPushItem
                    {
                        carrier = code,
                        number = item.TrackingNumber
                    });
                }
                catch (Exception ex)
                {
                    resultData.Add(new PostPushDataResultItem
                    {
                        IsSuccess = false,
                        FailMessage = ex.Message,
                        TrackingNumber = item.TrackingNumber
                    });
                }
            }
            try
            {
                var apiResult = await Push(waitUpdateData);
                foreach (var item in apiResult.data.rejected)
                {
                    if (item.error.code == -18019901)
                    {

                        resultData.Add(
                            new PostPushDataResultItem
                            {
                                IsSuccess = true,
                                TrackingNumber = item.number
                            });
                    }
                    else
                    {
                        resultData.Add(new PostPushDataResultItem
                        {
                            TrackingNumber = item.number,
                            FailMessage = item.error.message,
                            IsSuccess = false
                        });
                    }
                }
                foreach (var item in apiResult.data.accepted)
                {
                    resultData.Add(
                        new PostPushDataResultItem
                        {
                            IsSuccess = true,
                            TrackingNumber = item.number
                        });
                }
            }
            catch (Exception ex)
            {

                resultData.AddRange(waitUpdateData.Select(x => new PostPushDataResultItem
                {
                    TrackingNumber = x.number,
                    FailMessage = ex.Message,
                    IsSuccess = false
                }));
            }


            var result = new PostPushDataResult();
            result.Auth = apiKey;
            result.Items.AddRange(resultData);
            return result;
        }

        public override async Task<GetPushDataResult> GetWaitPushData(Empty request, ServerCallContext context)
        {

            GetPushDataResult result = new GetPushDataResult();
            try
            {
                //一次上传40个
                string sql = @"select top 40 a.TrackingNumber,c.FirstCode,c.Regex from Logistics_Trace(nolock)a join Logistics_Channel(nolock)b on a.ChannelId=b.Id
                                                             join Logistics_ChannelFirstCode(nolock)c on c.ChannelId=b.Id  
                                                        where b.Can17Tracking=1 and a.IsUpdate=0";
                var DbResult = await unitOfWork.QueryBySqlAsync<dynamic>(sql);
                result.Items.AddRange(DbResult.
                    Select(x => new PushDataItem
                    {
                        ServiceCode = x.FirstCode,
                        TrackingNumber = x.TrackingNumber
                    }));
                result.Success = true;
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.Message = ex.Message;
            }
            return result;
        }
    }
}