using GpsCardGatewayPosition.Common;
using GpsCardGatewayPosition.Common.Extract;
using GpsCardGatewayPosition.Common.Helper;
using GpsCardGatewayPosition.Model.Enum;
using GpsCardGatewayPosition.Model.IoT;
using GpsCardGatewayPosition.Service.Biz.Health;
using GpsCardGatewayPosition.Service.Biz;
using GpsCardGatewayPosition.Service.Biz.Location;
using GpsCardGatewayPosition.Service.Biz.Location.Dto;
using GpsCardGatewayPosition.Service.Biz.Location.Dto.Gaode;
using GpsCardGatewayPosition.Service.Biz.Location.Dto.Wayz;
using GpsCardGatewayPosition.Service.Biz.Pay;
using GpsCardGatewayPosition.Service.Biz.Sos;
using GpsCardGatewayPosition.Service.Cache;
using GpsCardGatewayPosition.Service.MqProducer;
using GpsCardGatewayPosition.Service.Resolver.Interface;
using GpsCardGatewayPosition.Service.Resolver.Property.Dto;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TelpoDataService.Util.Entities.GpsCard;
using GpsCardGatewayPosition.Model.Context;
using GpsCardGatewayPosition.Model.Templates;
using GpsCardGatewayPosition.Service.MqProducer.Model;
using TelpoDataService.Util.Entities.GpsLocationHistory;

namespace GpsCardGatewayPosition.Service.Resolver.Property
{
    public class GpsPositionResolver : IPropertyResolver
    {
        private readonly ILogger<GpsPositionResolver> _logger;

        private readonly GaodeService _serviceGaode;
        private readonly WayzService _serviceWayz;
        private readonly DeviceCacheManager _deviceCacheMgr;

        private readonly MqProcessLogic _serviceMqProcess;
        private readonly GlobalService _serviceGlobal;
        private readonly PayLogic _servicePay;
        private readonly SosLogic _serviceSos;
        private readonly HealthLogic _serviceHealth;
        private readonly LocationLogic _serviceLocation;


        private AsyncLocal<string> _messageId = new AsyncLocal<string>();
        private AsyncLocal<PropertyModel> _package = new AsyncLocal<PropertyModel>();
        private AsyncLocal<PropertyItemModel<GpsInfoModel>> _propertyValue = new AsyncLocal<PropertyItemModel<GpsInfoModel>>();
        public GpsPositionResolver(ILogger<GpsPositionResolver> logger,
           GaodeService serviceGaode, WayzService serviceWayz,
           LocationLogic serviceLocation, MqProcessLogic serviceMqProcess, GlobalService serviceGlobal, SosLogic serviceSos, PayLogic servicePay, HealthLogic serviceHealth,
           DeviceCacheManager deviceCacheMgr)
        {
            _logger = logger;

            _serviceGaode = serviceGaode;
            _serviceWayz = serviceWayz;
            _serviceLocation = serviceLocation;
            _serviceMqProcess = serviceMqProcess;
            _serviceSos = serviceSos;
            _servicePay = servicePay;
            _serviceHealth = serviceHealth;
            _serviceLocation = serviceLocation;
            _serviceGlobal = serviceGlobal;
            _deviceCacheMgr = deviceCacheMgr;
        }

        public void SetResolveInfo(PackageMsgModel msg)
        {
            _messageId.Value = msg.MessageId;
            _package.Value = ((JToken)msg.TopicInfo).ToObject<PropertyModel>()!;
            _propertyValue.Value = ((JToken)msg.DetailData).ToObject<PropertyItemModel<GpsInfoModel>>()!;
           
        }

        public override string ToString()
        {
            return $"{nameof(GpsPositionResolver)}[{_messageId.Value}]";
        }
        public async Task ExecuteMessageAsync()
        {
            var package = _package.Value;
            var serialno = package.DeviceName;  //设备序列号
            var messageId = _messageId.Value;
            var propertyValue = _propertyValue.Value;

            if (propertyValue == null) return;
            if (propertyValue.Value.Latitude == 0 || propertyValue.Value.Longitude == 0) return;

            //var device = await _deviceCacheMgr.GetDeviceBySerialNoAsync(messageId!, serialno!).ConfigureAwait(false);
            //if (device == null)
            //{
            //    _logger.LogError($"非法设备:{serialno}");
            //    return;
            //}
            var device = new GpsDevice()
            {
                DeviceId = serialno,
            };

            #region 定位解析
            decimal[] latLng = GeoConvert.ConvertGoogleBaiduLatLng(propertyValue.Value.Latitude, propertyValue.Value.Longitude);
            //var serviceResult = await _serviceGaode.GetGaodeReGeoAddressAsync(serialno, new GaodeGpsRequest(latLng[1], latLng[0])).ConfigureAwait(false);

            WayzGpsRequest wayzGpsRequest = new WayzGpsRequest
            {
                Location = new WayzRequest.LocationDetail
                {
                    //Gnss = new WayzRequest.Gnss
                    //{
                    //    Point = new WayzRequest.Point
                    //    {
                    //        Longitude = propertyValue.Value.Longitude,
                    //        Latitude = propertyValue.Value.Latitude,
                    //        //Longitude = latLng[1],
                    //        //Latitude = latLng[0],
                    //    }
                    //}

                    // 使用维智火星系坐标请求
                    Position = new WayzRequest.Postion
                    {
                        Point = new WayzRequest.Point
                        {
                            //Longitude = propertyValue.Value.Longitude,
                            //Latitude = propertyValue.Value.Latitude,
                            Longitude = latLng[1],
                            Latitude = latLng[0],
                        }
                    }
                },
                Asset = new WayzRequest.AssetDevice
                {
                    Id = serialno,
                    ImeiMd5 = serialno,
                    UniqueId = device.DeviceId
                }
            };
            var wayzServiceResult = await _serviceWayz.GetWayzReGeoAddressAsync(serialno, wayzGpsRequest).ConfigureAwait(false);
            //if (!wayzServiceResult.Flag) return;
            var province = string.Empty;
            var city = string.Empty;
            var district = string.Empty;
            var address = string.Empty;
            var cityCode = string.Empty;
            var hashParam = string.Empty;
            var fullAddress = string.Empty;

            if (wayzServiceResult.Flag)
            {
                province = wayzServiceResult.Province;
                city = wayzServiceResult.City;
                district = wayzServiceResult.District;
                address = wayzServiceResult.Address;
                cityCode = wayzServiceResult.CityCode;
                hashParam = wayzServiceResult.HashParam;
                fullAddress = wayzServiceResult.FullAddress;
            }
            else
            {
                _logger.LogInformation($"维智服务不能解析GPS逆地址数据,将采用高德服务解析");
                var gpsGaodeRequest = new GaodeGpsRequest(latLng[1], latLng[0]);
                var gaodeServiceResult = await _serviceGaode.GetGaodeReGeoAddressAsync(serialno, gpsGaodeRequest);
                if (gaodeServiceResult.Flag)
                {
                    province = gaodeServiceResult.Province;
                    city = gaodeServiceResult.City;
                    district = gaodeServiceResult.District;
                    address = gaodeServiceResult.Address;
                    cityCode = gaodeServiceResult.CityCode;
                    hashParam = gaodeServiceResult.HashParam;
                    fullAddress = string.Format("{0}|{1}", "_Gaode", gaodeServiceResult.Address);

                }
                else
                {
                    _logger.LogInformation($"维智服务和高德服务解析都不能解析GPS逆地址定位数据");
                    return;
                }
            }

            #endregion

            #region 保存历史轨迹

            int radius = 50;

            var loc = new LocationInfo
            {
                LocationId = Guid.NewGuid().ToString("D"),
                Address = address,//保存实际位置地址 "", 
                BaiduLat = latLng[2],
                BaiduLng = latLng[3],
                OLat = propertyValue.Value.Latitude,
                OLng = propertyValue.Value.Longitude,
                GLat = latLng[0],
                GLng = latLng[1],
                Course = Convert.ToInt32(propertyValue.Value.Altitude),
                DeviceId = device.DeviceId,
                DeviceStatus = radius.ToString(),
                IsStop = false,
                LastUpdate = Utils.ConvertToLocalDateTime(propertyValue.Time),
                UtcDate = Utils.ConvertToUtcDateTime(propertyValue.Time),
                LocationType = (int)LocationType.GPS,
                Remarks = cityCode,
                SerialNo = serialno,
                Speed = 0,
                Postcode = cityCode,
                IsRedressed = false,
                HashParam = hashParam,
                Province = province,
                City = city,
                District = district
            };

            loc.Remarks = string.Format("Wayz_Gps|{0}", fullAddress);

            //如果经纬度解析出来的地址包含特定内容,则替换为指定内容
            for (int i = 0; i < Backups.Addresses.Count; i++)
            {
                if (address.Contains(Backups.Addresses[i].Address) &&
                    city.Contains(Backups.Addresses[i].City))
                {
                    string index = i.ToString();
                    loc.Address = Backups.LonLatDict[index].Address;
                    loc.GLat = Backups.LonLatDict[index].GaodeLat;
                    loc.GLng = Backups.LonLatDict[index].GaodeLon;
                    break;
                }
            }

            var positionStatus = await _deviceCacheMgr.GetPositionStatusCacheAsync(serialno).ConfigureAwait(false);
            var requestPositionData = new RequestLocationInfo<WayzGpsRequest>
            {
                MapSource = 2,
                RequestLocationType = loc.LocationType,
                RequestData = wayzGpsRequest
            };
            var hisResult = await _serviceLocation.AddLocationAsync(messageId, loc, positionStatus, propertyValue.Time, wayzServiceResult.CityCode, null, requestPositionData).ConfigureAwait(false);
            if (!hisResult.IsSuccess)
            {
                _logger.LogError($"{hisResult.Message}");
                return;
            }
            #endregion

            #region 处理围栏
            //过滤历史定位消息
            if (!hisResult.IsHistoryLocation)
            {
                _serviceLocation.ProcessGeofence(loc, messageId);
            }
            else
            {
                _logger.LogInformation($"设备{serialno},收到历史定位");
            }
            #endregion

            #region 保存最后位置信息
            var context = "online=1";
            var deviceStatus = await _deviceCacheMgr.GetDeviceStatusBySerialNoAsync(messageId, serialno).ConfigureAwait(false);
            var statusContext = new DeviceStatus();
            if (deviceStatus != null)
            {
                statusContext.Deserlize(deviceStatus.DeviceStatus);
            }
            statusContext.Deserlize(context);

            //重新构造设备状态数据
            deviceStatus = new GpsDeviceStatus
            {
                Address = loc.Address,
                IsStop = (bool)loc.IsStop,
                BaiduLat = loc.BaiduLat,
                BaiduLng = loc.BaiduLng,
                Olat = loc.OLat,
                Olng = loc.OLng,
                Glat = loc.GLat,
                Glng = loc.GLng,
                Course = loc.Course,
                DeviceId = loc.DeviceId,
                DeviceStatus = statusContext.ToString(),
                DeviceUtcTime = loc.UtcDate,
                LastUpdate = loc.LastUpdate,
                LocationType = loc.LocationType,
                Remarks = loc.LocationId,
                Serialno = loc.SerialNo,
                //Speed = loc.Speed,
                Speed = SafeType.SafeInt(loc.DeviceStatus)
            };

            var result = await _serviceLocation.UpdateDeviceStatusAsync(messageId, deviceStatus).ConfigureAwait(false);
            if (!result.IsSuccess)
            {
                _logger.LogError($"{result.Message}");
                return;
            }

            //THOMAS Kafka
            var positionData = new LocationDatas()
            {
                imei = loc.SerialNo,
                altitude = 0,
                address = loc.Address,
                baiduLatitude = loc.BaiduLat,
                baiduLongitude = loc.BaiduLng,
                gaodeLatitude = loc.GLat,
                gaodeLongitude = loc.GLng,
                originalLatitude = loc.OLat,
                originalLongitude = loc.OLng,
                locationType = loc.LocationType,
                postcode = loc.Postcode,
                hashParam = loc.HashParam,
                radius = radius,
                province = province,
                city = city,
                district = district
            };

            await _serviceMqProcess.ProcessPositionAsync(messageId, positionData, loc.LastUpdate.Value.ToString("yyyy-MM-dd HH:mm:ss"));
            #endregion

            #region 更新Alarm
            if (propertyValue.Value.IDType == (int)IdType.Sos && !string.IsNullOrWhiteSpace(propertyValue.Value.IDNumber)) //SOS
            {
                // THOMAS Kafka
                //var SOSAlarm = new SoSTemplates()
                //{
                //	imei = serialno,
                //	sosId = propertyValue.Value.IDNumber,
                //	address = loc.Address,
                //	info = "您的宝贝在求救",
                //	baiduLatitude = loc.BaiduLat,
                //	baiduLongitude = loc.BaiduLng,
                //	gaodeLatitude = loc.GLat,
                //	gaodeLongitude = loc.GLng,
                //	originalLatitude = loc.OLat,
                //	originalLongitude = loc.OLng,
                //};
                //_serviceMqProcess.ProcessAlarmSos(messageId, SOSAlarm, loc.LastUpdate.Value.ToString("yyyy-MM-dd HH:mm:ss"));

                var sosId = propertyValue.Value.IDNumber;

                await _serviceSos.HandleSosAddressAsync(messageId, sosId, propertyValue.Time, () => new HisGpsAlarm
                {
                    DeviceId = device.DeviceId,
                    MessageId = sosId,
                    Serialno = serialno,
                    CreateTime = DateTime.Now,
                    DeviceUtcTime = Utils.ConvertToUtcDateTime(propertyValue.Time),

                    Olat = loc.OLat,
                    Olng = loc.OLng,
                    BaiduLat = loc.BaiduLat,
                    BaiduLng = loc.BaiduLng,
                    Glat = loc.GLat,
                    Glng = loc.GLng
                },
                a =>
                {
                    a.Olat = loc.OLat;
                    a.Olng = loc.OLng;
                    a.BaiduLat = loc.BaiduLat;
                    a.BaiduLng = loc.BaiduLng;
                    a.Glat = loc.GLat;
                    a.Glng = loc.GLng;
                    return a;
                },
                async () => {
                    var SOSAlarm = new SoSTemplates()
                    {
                        imei = serialno,
                        sosId = propertyValue.Value.IDNumber,
                        address = loc.Address,
                        info = "您的宝贝在求救",
                        baiduLatitude = loc.BaiduLat,
                        baiduLongitude = loc.BaiduLng,
                        gaodeLatitude = loc.GLat,
                        gaodeLongitude = loc.GLng,
                        originalLatitude = loc.OLat,
                        originalLongitude = loc.OLng,
                    };
                    await _serviceMqProcess.ProcessAlarmSosAsync(messageId, SOSAlarm, loc.LastUpdate.Value.ToString("yyyy-MM-dd HH:mm:ss"));
                });
            }
            else if (propertyValue.Value.IDType == (int)IdType.PayLog && !string.IsNullOrWhiteSpace(propertyValue.Value.IDNumber))
            {
                var payId = propertyValue.Value.IDNumber;
                var pay = await _servicePay.GetPayLogAsync(messageId, $"{serialno}-{payId}").ConfigureAwait(false);

                if (pay == null)
                {
                    pay = new GpsPayLog
                    {
                        Serialno = serialno,
                        Payid = $"{serialno}-{payId}",
                        DeviceId = device.DeviceId,

                        Olat = loc.OLat,
                        Olng = loc.OLng,
                        BaiduLat = loc.BaiduLat,
                        BaiduLng = loc.BaiduLng,
                        Glat = loc.GLat,
                        Glng = loc.GLng
                    };
                    await _servicePay.AddPayLogAsync(messageId, pay).ConfigureAwait(false);
                }
                else
                {
                    pay.Olat = loc.OLat;
                    pay.Olng = loc.OLng;
                    pay.BaiduLat = loc.BaiduLat;
                    pay.BaiduLng = loc.BaiduLng;
                    pay.Glat = loc.GLat;
                    pay.Glng = loc.GLng;
                    await _servicePay.UpdatePayLogAsync(messageId, pay).ConfigureAwait(false);
                }
            }
            else if (propertyValue.Value.IDType == (int)IdType.Temperature && !string.IsNullOrWhiteSpace(propertyValue.Value.IDNumber)) //温度上报(带地址)
            {
                var tempId = propertyValue.Value.IDNumber;

                await _serviceHealth.HandleTemperatureAddressAsync(messageId, $"{serialno}-{tempId}", () => new HisGpsTemperature
                {
                    TemperatureId = $"{serialno}-{tempId}",
                    Serialno = serialno,
                    Address = loc.Address,
                    Province = province,
                    City = city,
                    District = district,
                    LastUpdate = Utils.ConvertToLocalDateTime(propertyValue.Time),
                    TempId = tempId
                },
                a =>
                {
                    a.Address = loc.Address;
                    a.Province = province;
                    a.City = city;
                    a.District = district;
                    return a;
                });
            }
            #endregion
        }


    }
}