using System.Collections.Concurrent;
using System.Dynamic;
using System.Net;
using System.Net.Http.Headers;
using System.Text;
using Infrastructure.Cache;
using Infrastructure.CloudSdk;
using Infrastructure.CloudSdk.minio;
using Infrastructure.CloudSdk.wayline;
using Infrastructure.Extensions;
using Infrastructure.Helpers;
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using MetadataExtractor.Formats.Xmp;
using Microsoft.Extensions.Logging;
using MQTTnet.Client;
using Newtonsoft.Json;
using OpenAuth.App.ServiceApp;
using OpenAuth.App.ServiceApp.FlyTask.Request;
using OpenAuth.Repository.Domain;
using OpenAuth.WebApi;
using Quartz;
using SqlSugar;

namespace OpenAuth.App.BaseApp.Subscribe;

public class ConfigSubscribe : IJob
{
    private readonly MqttClientManager _mqttClientManager;
    private readonly ISqlSugarClient _sqlSugarClient;
    private readonly RedisCacheContext _redisCacheContext;
    private readonly ManageApp _manageApp;
    private readonly MinioService _minioService;
    private object _locker = new();
    private object _dockUploadFileLocker = new();
    private readonly ILogger<ConfigSubscribe> _logger;
    private readonly ConcurrentDictionary<string, DateTime> _processedMessages = new();
    private readonly TimeSpan _deduplicationWindow = TimeSpan.FromMinutes(1);

    public ConfigSubscribe(MqttClientManager mqttClientManager, ISqlSugarClient sqlSugarClient,
        ICacheContext redisCacheContext, ManageApp manageApp, MinioService minioService,
        ILogger<ConfigSubscribe> logger)
    {
        _mqttClientManager = mqttClientManager;
        _sqlSugarClient = sqlSugarClient;
        _redisCacheContext = redisCacheContext as RedisCacheContext;
        _manageApp = manageApp;
        _minioService = minioService;
        _logger = logger;
    }

    public async Task Execute(IJobExecutionContext context)
    {
        await Subscribe();
    }

    private async Task Subscribe()
    {
        // 或者 thing/product/#
        // sys/product/#
        string[] topicList =
        {
            "thing/product/+/services_reply",
            "thing/product/+/events",
            "thing/product/+/requests",
            //"thing/product/+/osd",
            //"thing/product/+/status"
        };
        _logger.LogInformation("开启监听");
        await _mqttClientManager
            .SubscribeAsync(topicList,
                async (args) =>
                {
                    //args.IsHandled = false; // todo 待实验确定
                    //args.AutoAcknowledge = true; // todo 待实验确定
                    await HandleTopic(args, args.ApplicationMessage.Topic,
                        Encoding.UTF8.GetString(args.ApplicationMessage.Payload));
                });
    }


    private async Task HandleTopic(MqttApplicationMessageReceivedEventArgs args, string topic,
        string message)
    {
        /*
         thing/product/{device_sn}/osd 设备端定频向云平台推送的设备属性（properties），
        具体内容范围参见物模型内容
        thing/product/{device_sn}/state 设备端按需上报向云平台推送的设备属性（properties），
        具体内容范围参见物模型内容
        thing/product/{gateway_sn}/services_reply 设备对 service 的回复、处理结果 （航线任务下发之类的）
        thing/product/{gateway_sn}/events 设备端向云平台发送的，需要关注和处理的事件。
        比如SD满了，飞机解禁禁飞区等信息（事件范围参见物模型内容）
        thing/product/{gateway_sn}/requests 设备端向云平台发送请求，为了获取一些信息，比如上传的临时凭证
        sys/product/{gateway_sn}/status 	设备上下线、更新拓扑
        thing/product/{gateway_sn}/property/set_reply 设备属性设置的响应
        thing/product/{gateway_sn}/drc/up DRC 协议上行*/

        var sn = topic.Split("/")[2];
        var tempStr = topic.Replace(sn, "*");
        //Console.WriteLine($"成功调用主题 [{topic}] 的消息: {message}");
        // 主题方法
        var result = JsonConvert.DeserializeObject<TopicServicesRequest<dynamic>>(message);
        var method = result.method;
        var data = result.data;
        //_logger.LogInformation($"主题：{topic}\n消息：{message}");
        long code = 0;
        switch (tempStr)
        {
            case "thing/product/*/requests":
                switch (method)
                {
                    // 临时凭证上传
                    case "storage_config_get":
                        _logger.LogInformation($"进入临时凭证获取处理");
                        // {"bid":"afc5c13e-da1c-4a15-aec1-a765aac34c57",
                        // "data":{"module":0},
                        // "method":"storage_config_get",
                        // "need_reply":0,"tid":"50e8102c-da72-42b1-a899-a82a519456d9",
                        // "timestamp":1750575776430,
                        // "gateway":"8UUXN5400A079H"}
                        // 配置中读取minio配置
                        var storageConfigRequest = new TopicServicesRequest<object>()
                        {
                            method = "storage_config_get",
                            tid = result.tid,
                            bid = result.bid,
                            timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                            data = new
                            {
                                result = 0,
                                output = new
                                {
                                    bucket = _minioService._bucketName,
                                    endpoint = $"http://{_minioService.endPoint}",
                                    object_key_prefix = Guid.NewGuid().ToString(), // todo 是否设计任务id ？
                                    provider = "minio",
                                    region = "linyi",
                                    credentials = new
                                    {
                                        access_key_id = $"{_minioService.AccessKey}",
                                        access_key_secret = $"{_minioService.SecretKey}",
                                        expire = 3600,
                                        security_token = ""
                                    }
                                }
                            }
                        };
                        // thing/product/{gateway_sn}/requests_reply
                        var tempTopic = $"thing/product/{sn}/requests_reply";
                        await _mqttClientManager.PublishAsync(tempTopic,
                            JsonConvert.SerializeObject(storageConfigRequest));
                        break;
                    case "flight_areas_get":
                        //Console.WriteLine("跳过自定义飞行区文件获取");
                        break;
                    // 获取航线
                    case "flighttask_resource_get":
                        string flightId = data.flight_id + "";
                        _logger.LogInformation($"进入资源获取处理: 任务id {flightId}");
                        // eb87b257-5af1-4bf1-9aba-4267be9fdb12 flight 
                        // http://175.27.168.120:6013/test/2025062209390863860047.kmz
                        // md5  585c833012ddb794eaac1050ef71aa31
                        // 这一小段运行异常
                        var taskAssign = await _sqlSugarClient
                            .Queryable<LasaTaskAssign>()
                            .Where(x => x.FlightId == flightId)
                            .SingleAsync();
                        _logger.LogInformation($"任务信息：{JsonConvert.SerializeObject(taskAssign)}");
                        /*var taskAssign =
                            manageApp.GetTaskAssignByBidAndTid(result.bid, result.tid, flightId);*/
                        var flightTaskResourceGetTopic = $"thing/product/{sn}/requests_reply";
                        dynamic outData = new ExpandoObject();
                        outData.result = 0;
                        outData.output = new
                        {
                            file = new
                            {
                                fingerprint = taskAssign.Md5,
                                url = taskAssign.Wpml
                            }
                        };
                        var outRequest = new TopicServicesRequest<object>()
                        {
                            bid = result.bid,
                            data = outData,
                            tid = result.tid,
                            timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                            method = "flighttask_resource_get"
                        };

                        /*Console.WriteLine(
                            $"topic: {flightTaskResourceGetTopic} 发送资源获取处理结果：{JsonConvert.SerializeObject(outRequest)}");*/
                        await _mqttClientManager.PublishAsync(flightTaskResourceGetTopic,
                            JsonConvert.SerializeObject(outRequest));
                        break;
                    case "config":
                        break;
                    default:
                        _logger.LogInformation($"未处理消息：{message}");
                        break;
                }

                break;
            case "thing/product/*/events":
                switch (method)
                {
                    case "file_upload_callback":
                        // 文件上传
                        _logger.LogDebug("进入文件上传处理");
                        _logger.LogDebug($"文件上传处理：{message}");
                        //飞行任务 0 手飞任务 1 
                        // todo 如果是手飞任务，生成任务 关于任务类型？
                        int flightType = data.flight_task.flight_type;
                        string flightId = data.file.ext.flight_id;
                        // 关于flightId 没有值的问题怎么办？？？
                        var taskAssign = _manageApp.GetTaskAssignByFlightId(flightId);
                        var taskId = "";
                        var taskName = "";
                        var workspaceId = "";
                        if (taskAssign != null)
                        {
                            taskId = taskAssign.TaskId;
                            var executeTask = await _sqlSugarClient
                                .Queryable<LasaTask>()
                                .SingleAsync(a => a.Id == taskId);
                            if (!string.IsNullOrEmpty(executeTask.TaskName))
                            {
                                taskName = executeTask.TaskName;
                            }

                            if (!string.IsNullOrEmpty(executeTask.WorkspaceId))
                            {
                                workspaceId = executeTask.WorkspaceId;
                            }
                        }
                        else
                        {
                            taskName = "手飞任务";
                        }

                        string objectKey = data.file.object_key;
                        var folderKey = ((string)data.file.object_key).Split("/");
                        var parentKey = folderKey[2];
                        if (flightType.Equals(1))
                        {
                            parentKey = flightId;
                        }

                        var isExist = await _sqlSugarClient
                            .Queryable<LasaMediaFile>()
                            .Where(x => x.Id.Equals(parentKey)).CountAsync();
                        if (isExist == 0)
                        {
                            var date = DateTime.Now;
                            var timeStr = date.ToString("yyyy-MM-dd HH:mm:ss");
                            var parent1 = new LasaMediaFile()
                            {
                                Id = parentKey,
                                FlightId = flightId,
                                TaskId = taskId,
                                ParentKey = "0",
                                Name = $"{taskName} {timeStr}",
                                WorkspaceId = workspaceId,
                                CreateTime = date,
                            };
                            await _sqlSugarClient.Insertable(parent1).ExecuteCommandAsync();
                        }

                        // 重复检测
                        var mediaFile = await _sqlSugarClient
                            .Queryable<LasaMediaFile>()
                            .Where(a => a.FlightId.Equals(flightId))
                            .Where(a => a.ObjectKey.Equals(objectKey)).SingleAsync();
                        if (mediaFile == null)
                        {
                            var type = 0;
                            var preSize = 1;
                            // 判断是不是图片
                            if (objectKey.EndsWith(".jpeg")) // todo 是否有其它类型的图片，待确定
                            {
                                preSize = 65535;
                                var fileName = Path.GetFileNameWithoutExtension(objectKey);
                                var fileNameParts = fileName.Split("_");
                                var suffix = fileNameParts[^1];
                                type = suffix switch
                                {
                                    //  0 未知 1 可见光 2 红外 3 变焦 4.广角 5 视频
                                    "V" => 1,
                                    "T" => 2,
                                    "Z" => 3, // 变焦
                                    "W" => 4, // 广角
                                    _ => type
                                };
                            }
                            else if (objectKey.EndsWith(".mp4"))
                            {
                                type = 5;
                            }

                            string suoluokey = "";
                            long? fileSize = 0;
                            int width = 0, height = 0, focalLength = 0;
                            int offset = 0, length = 0;
                            string model = "";
                            float? gimbalRoll = 0, gimbalPitch = 0;
                            float? digitalZoomRatio = 1;
                            var fileUrl = "http://" + _minioService.endPoint + "/" + _minioService._bucketName +
                                          "/" + objectKey;
                            using (var httpClient = new HttpClient())
                            {
                                suoluokey = "minipic/" + data.file.name.ToString();
                                // 目前读取64KB
                                // 添加Range请求头
                                httpClient.DefaultRequestHeaders.Range =
                                    new RangeHeaderValue(0, preSize);
                                try
                                {
                                    var response = httpClient
                                        .GetAsync(fileUrl, HttpCompletionOption.ResponseHeadersRead).Result;
                                    if (response.StatusCode == HttpStatusCode.PartialContent)
                                    {
                                        var contentRange = response.Content.Headers.ContentRange;
                                        if (contentRange != null)
                                        {
                                            fileSize = contentRange.Length.Value;
                                        }

                                        if (objectKey.ToLower().EndsWith("jpeg"))
                                        {
                                            // 成功获取部分内容
                                            var y = response.Content.ReadAsByteArrayAsync().Result;
                                            var ms = new MemoryStream(y);
                                            var directories = ImageMetadataReader.ReadMetadata(ms);
                                            // 获取 XMP 目录（包含 XMP 原始 XML 数据）
                                            var xmpDirectory = directories.OfType<XmpDirectory>().FirstOrDefault();
                                            if (xmpDirectory != null)
                                            {
                                                // 获取 XMP 的 XML 字符串（原始数据）
                                                var xmpXml = xmpDirectory.GetXmpProperties();
                                                foreach (var keyValuePair in xmpXml)
                                                {
                                                    switch (keyValuePair.Key)
                                                    {
                                                        //     // drone-dji:GimbalPitchDegree: -90.00
                                                        //drone-dji:GimbalReverse: 0
                                                        //drone-dji:GimbalRollDegree: +180.00
                                                        //drone-dji:GimbalYawDegree: -96.40
                                                        case "drone-dji:GimbalPitchDegree":
                                                            gimbalPitch = float.Parse(keyValuePair.Value);
                                                            break;
                                                        case "drone-dji:GimbalRollDegree":
                                                            gimbalRoll = float.Parse(keyValuePair.Value);
                                                            break;
                                                    }
                                                }
                                            }

                                            foreach (var directory in directories)
                                            {
                                                if (directory is ExifDirectoryBase)
                                                {
                                                    if (directory.Name.Equals("Exif IFD0"))
                                                    {
                                                        foreach (var tag in directory.Tags)
                                                        {
                                                            if (tag.Name.Equals("Model"))
                                                            {
                                                                model = tag.Description;
                                                            }
                                                        }
                                                    }

                                                    if (directory.Name.Equals("Exif SubIFD"))
                                                    {
                                                        // Digital Zoom Ratio: 1 Exif SubIFD
                                                        foreach (var tag in directory.Tags)
                                                        {
                                                            if (tag.Name.Equals("Digital Zoom Ratio"))
                                                            {
                                                                digitalZoomRatio = float.Parse(tag.Description);
                                                            }

                                                            if (tag.Name.Equals("Exif Image Width"))
                                                            {
                                                                width = int.Parse(tag.Description.Replace("pixels", "")
                                                                    .Trim());
                                                            }

                                                            if (tag.Name.Equals("Exif Image Height"))
                                                            {
                                                                height = int.Parse(tag.Description.Replace("pixels", "")
                                                                    .Trim());
                                                            }

                                                            if (tag.Name.Equals("Focal Length 35"))
                                                            {
                                                                focalLength = int.Parse(tag.Description
                                                                    .Replace("mm", "")
                                                                    .Trim());
                                                            }
                                                        }
                                                    }

                                                    //Console.WriteLine(directory.Name);
                                                    if (directory.Name.Equals("Exif Thumbnail"))
                                                    {
                                                        foreach (var tag in directory.Tags)
                                                        {
                                                            if (tag.Name.Equals("Thumbnail Offset"))
                                                            {
                                                                offset = int.Parse(tag.Description.Replace("bytes", "")
                                                                    .Trim());
                                                            }

                                                            if (tag.Name.Equals("Thumbnail Length"))
                                                            {
                                                                length = int.Parse(tag.Description.Replace("bytes", "")
                                                                    .Trim());
                                                            }
                                                        }
                                                    }
                                                }
                                            }

                                            ms.Seek(offset + 6, SeekOrigin.Begin);
                                            byte[] buffer = new byte[length];
                                            int bytesRead = ms.Read(buffer, 0, length);
                                            // 上传缩略图到MinIO
                                            await _minioService.PutObjectAsync("", data.file.name.ToString(), suoluokey,
                                                new MemoryStream(buffer));
                                        }
                                    }
                                    else if (response.StatusCode == HttpStatusCode.OK)
                                    {
                                        // 服务器不支持Range请求，返回完整内容
                                        throw new InvalidOperationException("服务器不支持Range请求");
                                    }
                                    else
                                    {
                                        throw new HttpRequestException($"请求失败: {response.StatusCode}");
                                    }
                                }
                                catch (Exception ex)
                                {
                                    throw new Exception($"执行错误: {ex.Message}", ex);
                                }
                            }

                            var createdTimeStr = (string)data.file.metadata.created_time;
                            var createTime = string.IsNullOrEmpty(createdTimeStr)
                                ? DateTime.Now
                                : createdTimeStr.ToDateTime();
                            _logger.LogDebug("执行到保存媒体文件之前");
                            var fileUpload = new LasaMediaFile()
                            {
                                Id = Guid.NewGuid().ToString(),
                                FlightId = flightId, // 计划id
                                TaskId = taskId, // 任务id 
                                DroneModelKey = data.file.ext.drone_model_key, // 无人机型号
                                PayloadModelKey = data.file.ext.payload_model_key, //这应该可以标明是什么设置
                                IsOriginal = data.file.ext.is_original,
                                MediaIndex = data.file.ext.media_index,
                                AbsoluteAltitude = data.file.metadata.absolute_altitude, // 拍摄绝对高度
                                GimbalYawDegree = data.file.metadata.gimbal_yaw_degree, //云台偏航角度
                                RelativeAltitude = data.file.metadata.relative_altitude, // 拍摄相对高度
                                Lat = data.file.metadata.shoot_position.lat,
                                Lng = data.file.metadata.shoot_position.lng,
                                Name = data.file.name,
                                ObjectKey = data.file.object_key,
                                Path = data.file.path, // 目前这个好像没有值
                                CreateTime = createTime,
                                WorkspaceId = workspaceId,
                                ParentKey = parentKey,
                                Tid = result.tid,
                                Bid = result.bid,
                                FlightType = flightType,
                                Width = width,
                                Height = height,
                                minipic = suoluokey,
                                Size = fileSize,
                                ShowOnMap = 1,
                                display = 1,
                                FocalLength = focalLength,
                                PayloadModelName = model,
                                Type = type,
                                GimbalPitchDegree = gimbalPitch,
                                GimbalRollDegree = gimbalRoll,
                                DigitalZoomRatio = digitalZoomRatio
                            };
                            // 添加事务
                            await _sqlSugarClient.Insertable(fileUpload).ExecuteCommandAsync();
                        }

                        if (result.need_reply.Equals(1))
                        {
                            var fileUploadCallbackEventReply = new FileUploadCallbackEventReply<object>()
                            {
                                bid = result.bid,
                                tid = result.tid,
                                method = "file_upload_callback",
                                gateway = sn,
                                data = new
                                {
                                    result = 0
                                },
                                timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                            };
                            _ = _mqttClientManager.PublishAsync($"thing/product/{sn}/events_reply",
                                JsonConvert.SerializeObject(fileUploadCallbackEventReply));
                        }

                        var expectFileCount = data.flight_task.expected_file_count;
                        var uploadedFileCount = data.flight_task.uploaded_file_count;

                        var taskRecord = new LasaTask()
                        {
                            Id = taskId,
                            ExpectedFileCount = expectFileCount, // 期望文件数量
                            UploadedFileCount = uploadedFileCount // 已上传文件数量
                        };
                        //  当expectFileCount 等于uploadedFileCount时，则表示航线执行完成
                        /*
                        if (uploadedFileCount.Equals(expectFileCount))
                        {
                            taskRecord.Status = 5; // 成功状态
                        }
                        */

                        await _sqlSugarClient.Updateable(taskRecord)
                            .IgnoreNullColumns().ExecuteCommandAsync();

                        break;
                    case "release_terminal_control_area":
                        //暂不处理
                        break;
                    case "flighttask_progress":
                    {
                        // current_step
                        // "0":"初始状态"
                        // "1":"启动前检查，飞行器是否在执行航线中"
                        // "2":"启动前检查，机场是否退出工作模式"
                        // "3":"启动前检查，航线执行中"
                        // "4":"启动前检查，返航中"
                        // "5":"航线执行进入准备状态，开始等待任务下发"
                        // "6":"机场进入工作状态"
                        // "7":"进入开机检查准备工作和开盖准备工作"
                        // "8":"图传远程对频"
                        // "9":"等待飞行系统准备就绪，推送连接建立"
                        // "10":"等待 RTK 源监听有值上报"
                        // "11":"检查 RTK 源是否是机场源，如果不是要重新设置"
                        // "12":"等待飞行控制权通知"
                        // "13":"机场无控制权，抢夺飞行器控制权"
                        // "14":"自定义飞行区一致性检查"
                        // "15":"离线地图一致性检查"
                        // "16":"获取最新 KMZ URL"
                        // "17":"下载 KMZ"
                        // "18":"KMZ 上传中"
                        // "19":"染色配置"
                        // "20":"飞行器起飞参数设置，备降点设置，起飞高度设置，染色设置"
                        // "21":"飞行器 flyto 起飞参数设置"
                        // "22":"起飞机场检查降落机场准备状态"
                        // "23":"Home 点设置"
                        // "24":"触发执行航线"
                        // "25":"航线执行中"
                        // "26":"进入返航的检查准备工作"
                        // "27":"飞行器降落机场"
                        // "28":"降落以后的关盖"
                        // "29":"机场退出工作模式"
                        // "30":"机场异常恢复","31":"机场上传飞行系统日志","32":"相机录像状态检查","33":"获取媒体文件数量","34":"机场起飞开盖的异常恢复","35":"通知任务结果","36":"日志列表拉取 - 飞行器列表","37":"日志列表拉取 - 拉取机场列表","38":"日志列表拉取 - 上传日志列表结果","39":"日志拉取-拉取飞行器日志","40":"日志拉取-拉取机场日志","41":"日志拉取-压缩飞行器日志","42":"日志拉取-压缩机场日志","43":"日志拉取-上传飞行器日志","44":"日志拉取-上传机场日志","45":"日志拉取-通知结果","46":"自定义飞行区文件更新准备中","47":"自定义飞行区更新中","48":"离线地图更新准备中","49":"离线地图更新中","65533":"结束后等待服务回包","65534":"无具体状态","65535":"UNKNOWN"}
                        var isHandle = IsDuplicate(Md5.Encrypt(message));
                        _logger.LogDebug($"md5: {isHandle} 重复否：{IsDuplicate(Md5.Encrypt(message))} 信息：{message} ");
                        if (isHandle)
                        {
                            _logger.LogInformation("跳过处理");
                            break;
                        }
                        _logger.LogDebug("航线进度未跳过处理");
                        code = data.result; // result 

                        var waylineMissionState = (int)data.output.ext.wayline_mission_state;
                        string flightId1 = (string)data.output.ext.flight_id;
                        var taskAssign1 = _manageApp.GetTaskAssignByFlightId(flightId1);
                        // 处理航线进度 ，也有可能是失败
                        if (code != 0)
                        {
                            Console.WriteLine($"航线进度错误信息：{ErrorMap[code]} {message}");
                            // 取消任务
                            var cancelTaskTopic = $"thing/product/{sn}/services";
                            var cancelTaskRequest = new TopicServicesRequest<object>()
                            {
                                method = "flighttask_undo",
                                tid = result.tid,
                                bid = result.bid,
                                timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                                data = new
                                {
                                    flight_ids = new[] { data.output.ext.flight_id }
                                }
                            };
                            await _mqttClientManager.PublishAsync(cancelTaskTopic,
                                JsonConvert.SerializeObject(cancelTaskRequest));
                            //更新任务状态及失败原因？

                            // "773":"低电量返航导致航线中断"
                            int reasonCode = data.output.ext.break_point.break_reason;
                            // 添加断点信息
                            var taskRecord1 = new LasaTask()
                            {
                                Id = taskAssign1.TaskId,
                                Status = 2,
                                Reason = ErrorMap[code],
                                BreakPoint = JsonConvert.SerializeObject(data.output.ext.break_point)
                            };
                            // 创建一个条件任务怎么样？
                            await _sqlSugarClient.Updateable(taskRecord1)
                                .IgnoreNullColumns().ExecuteCommandAsync();
                            // todo 关于断点原因为773(电量低)，处置
                        }
                        else
                        {
                            var step = (int)data.output.progress.current_step;
                            _logger.LogDebug($"航线进度：{waylineMissionState} {step} {message}");
                            if (step.Equals(25)) // 航线执行
                            {
                                var task = await _sqlSugarClient.Queryable<LasaTask>()
                                    .FirstAsync(y => y.Id == taskAssign1.TaskId);
                                if (task != null && !string.IsNullOrEmpty(task.AIInspection) &&
                                    task.AIInspection.Equals("true") && string.IsNullOrEmpty(task.PushUrl))
                                {
                                    _logger.LogDebug("执行AI 智能巡检。。。。。");
                                    var rtmp = "rtmp://box.wisestcity.com:1935/live/7";
                                    var param = @$"{{
                                            ""bid"": ""{Guid.NewGuid().ToString()}"",
                                            ""method"": ""live_start_push"",
                                            ""tid"": ""{Guid.NewGuid().ToString()}"",
                                            ""timestamp"": {DateTimeOffset.Now.ToUnixTimeMilliseconds()},
                                            ""data"": {{
                                                ""url_type"": 1,
                                                ""url"": ""{rtmp}"",
                                                ""video_id"": ""1581F8HGX254V00A0BUY/99-0-0/normal-0"",
                                                ""video_quality"": 3
                                                }}
                                        }}";
                                    _logger.LogDebug($"直播参数：{param}");
                                    var topicRequest = $"thing/product/{sn}/services";
                                    await _mqttClientManager.PublishAsync(topicRequest, param);
                                    var req = new CallAiModel { TaskId = taskAssign1.TaskId ,RtmpUrl = rtmp};
                                    await _manageApp.CallAiModel(req);
                                }
                            }

                            // 航线成功
                            if (waylineMissionState.Equals(9)) // 航结结束，更新任务状态
                            {
                                var task = await _sqlSugarClient.Queryable<LasaTask>()
                                    .FirstAsync(y => y.Id == taskAssign1.TaskId);
                                if (!string.IsNullOrEmpty(task.AIInspection) && task.AIInspection.Equals(true) &&
                                    !string.IsNullOrEmpty(task.PushUrl))
                                {
                                    // todo 停止直播
                                    // todo 停止 aimodel 运行
                                    var para = @$"{{
	                                    ""bid"": {Guid.NewGuid().ToString()},
	                                    ""data"": {{
		                                ""video_id"": ""1581F8HGX254V00A0BUY/99-0-0/normal-0""
	                                    }},
	                                    ""tid"":{Guid.NewGuid().ToString()},
	                                    ""timestamp:"": {DateTimeOffset.Now.ToUnixTimeMilliseconds()},
	                                    ""method"": ""live_stop_push""
                                    }}";
                                    var topicRequest = $"thing/product/{sn}/services";
                                    await _mqttClientManager.PublishAsync(topicRequest, para);
                                    using var httpClient = new HttpClient();
                                    await httpClient.PostAsync("http://192.168.10.131:9025/stop_detection", null);
                                }

                                var record = new LasaTask()
                                {
                                    Id = taskAssign1.TaskId,
                                    Status = 5
                                };
                                await _sqlSugarClient.Updateable(record).IgnoreNullColumns().ExecuteCommandAsync();
                            }
                        }

                        /*if (result.need_reply.Equals(1))
                        {
                            var fileUploadCallbackEventReply = new FileUploadCallbackEventReply<object>()
                            {
                                bid = result.bid,
                                tid = result.tid,
                                method = "flighttask_progress",
                                gateway = sn,
                                data = new
                                {
                                    result = 0
                                },
                                timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
                            };
                            await _mqttClientManager.PublishAsync($"thing/product/{sn}/events_reply",
                                JsonConvert.SerializeObject(fileUploadCallbackEventReply));
                        }*/

                        //Console.WriteLine($"航线进度：{message}");
                        break;
                    }
                    default:
                    {
                        if (!method.Equals("hms"))
                        {
                            //Console.WriteLine($"未处理事件events：{message}");
                        }

                        break;
                    }
                }

                break;
            // 任务资源处理
            // 航线进度处理
            // 任务取消 thing/product/*/services_reply
            case "thing/product/*/services_reply":
                switch (method)
                {
                    case "live_start_push":
                        if (IsDuplicate(Md5.Encrypt(message)))
                        {
                            break;
                        }
                        _logger.LogDebug($"开启直播成功 {message}");
                        break;
                    case "live_stop_push":
                        _logger.LogDebug($"停止直播成功 {message}");
                        break;
                    case "flighttask_prepare": // 下发任务响应
                        // 顺序处理，多余的不再处理
                        lock (_locker)
                        {
                            // 报错处理
                            Console.WriteLine("进入prepare订阅消息");
                            code = data.result;
                            var taskAssign = _manageApp.GetTaskAssignByBidAndTid(result.bid, result.tid);
                            //Console.WriteLine($"prepare 任务信息：{JsonConvert.SerializeObject(taskAssign)}");
                            if (code == 0)
                            {
                                if (taskAssign == null)
                                {
                                    Console.WriteLine("已跳过prepare处理");
                                    return; // 不存在不操作
                                }

                                var flightId = taskAssign.FlightId;
                                var request = new TopicServicesRequest<object>();
                                dynamic data1 = new ExpandoObject();
                                data1.flight_id = flightId;
                                // todo 检查设备是否在线
                                request.SetMethod("flighttask_execute")
                                    .SetTid(result.tid)
                                    .SetBid(result.bid)
                                    .SetTimestamp(DateTimeOffset.Now.ToUnixTimeMilliseconds())
                                    .SetData(data1);
                                // 任务执行
                                _ = _mqttClientManager.PublishAsync($"thing/product/{sn}/services",
                                    JsonConvert.SerializeObject(request));
                                var taskAssignRecord = new LasaTaskAssign()
                                {
                                    Id = taskAssign.Id,
                                    Status = 1
                                };
                                _sqlSugarClient.Updateable(taskAssignRecord).IgnoreNullColumns()
                                    .ExecuteCommand();
                                var taskRecord = new LasaTask()
                                {
                                    Id = taskAssign.TaskId,
                                    FlightId = flightId,
                                };
                                _sqlSugarClient.Updateable(taskRecord).IgnoreNullColumns()
                                    .ExecuteCommand();
                                // todo 锁定这个机场 ，不再执行其它任务
                            }
                            else
                            {
                                // 错误处理
                                var errorMsg = ErrorMap[code];
                                var taskAssignRecord = new LasaTaskAssign()
                                {
                                    Id = taskAssign.Id,
                                    Reason = errorMsg,
                                    Status = 2
                                };
                                _sqlSugarClient.Updateable(taskAssignRecord).IgnoreNullColumns().ExecuteCommand();
                                var taskUpdate = new LasaTask
                                {
                                    Id = taskAssign.TaskId,
                                    Status = 2, // todo 状态待定
                                    Reason = errorMsg //失败原因
                                };
                                _sqlSugarClient.Updateable(taskUpdate).IgnoreNullColumns().ExecuteCommand();
                            }
                        }

                        break;
                    case "flighttask_execute": // 执行任务响应
                        code = data.result;
                        var taskAssignExecute = _manageApp.GetTaskAssignByBidAndTid(result.bid, result.tid, 1);
                        var taskRecordExecute = new LasaTask()
                        {
                            Id = taskAssignExecute.TaskId,
                        };
                        if (code != 0)
                        {
                            var errorMsg = ErrorMap[code];
                            //Console.WriteLine($"任务失败: 错误码 {code} 错误信息 {errorMsg}");
                            // 任务执行失败
                            // TOdo 和航线进度方法中返回的错误有没有区别 ？？？？
                            taskRecordExecute.Status = 2;
                            taskRecordExecute.Reason = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {errorMsg}（错误码： {code}）";
                        }
                        else
                        {
                            // 任务开始执行
                            taskRecordExecute.Status = 1; // 任务执行中
                            Console.WriteLine($"任务执行响应 {code} {message}");
                        }

                        await _sqlSugarClient.Updateable(taskRecordExecute).IgnoreNullColumns().ExecuteCommandAsync();
                        break;
                }

                break;
            case "thing/product/*/osd":
                // todo 处理保存 减少三位，保存
                // todo 字段信息
                Console.WriteLine($"osd消息: {message}");
                break;
            default:
                Console.WriteLine($"未进入主题处理");
                break;
        }
    }

    public DateTime GetDateTimeFromSeconds(long miliseconds)
    {
        var seconds = miliseconds / 1000; // 去除末尾三位
        return DateTimeOffset.FromUnixTimeSeconds(seconds).DateTime;
    }


    public bool IsDuplicate(string messageId)
    {
        var now = DateTime.UtcNow;
        // 清理过期消息
        foreach (var kvp in _processedMessages)
        {
            if (now - kvp.Value > _deduplicationWindow)
            {
                _processedMessages.TryRemove(kvp.Key, out _);
            }
        }

        // 检查是否已存在
        if (_processedMessages.ContainsKey(messageId))
        {
            return true;
        }

        _processedMessages[messageId] = now;
        return false;
    }

    public static Dictionary<long, string> ErrorMap = new()
    {
        { 312014, "设备升级中，请勿重复操作" },
        { 312015, "机场：{dock_org_name},业务繁忙无法进行设备升级，请等待机场处于空闲中后再试" },
        { 312016, "升级失败，机场和飞行器图传链路异常，请重启机场和飞行器后重试" },
        { 312022, "飞行器开机失败或未连接，请检查飞行器是否在舱内，是否安装电池，机场和飞行器是否已对频" },
        { 312023, "推杆闭合失败无法升级飞行器，请检查急停按钮是否被按下，推杆是否有异物卡住" },
        { 312027, "升级失败，机场未检测到飞行器" },
        { 312028, "升级失败，设备升级过程中设备被重启" },
        { 312029, "设备重启中无法进行设备升级，请等待设备重启完成后重试" },
        { 312030, "升级失败，飞行器增强图传开启后无法升级，请关闭飞行器增强图传后重试" },
        { 312704, "设备电量过低，请充电至20%以上后重试" },
        { 314000, "设备当前无法支持该操作，建议检查设备当前工作状态" },
        { 314001, "飞行任务下发失败，请稍后重试" },
        { 314002, "飞行任务下发失败，请稍后重试" },
        { 314003, "航线文件格式不兼容，请检查航线文件是否正确" },
        { 314005, "飞行任务下发失败，请稍后重试或重启机场后重试" },
        { 314006, "飞行器初始化失败，请重启机场后重试" },
        { 314007, "机场传输航线至飞行器失败，请重启机场后重试" },
        { 314008, "飞行器起飞前准备超时，请重启机场后重试" },
        { 314009, "飞行器初始化失败，请重启机场后重试" },
        { 314010, "航线执行失败，请重启机场后重试" },
        { 314011, "机场系统异常，无法获取飞行任务执行结果" },
        { 314012, "飞行器起飞前准备失败，无法执行飞行任务，请重启机场后重试" },
        { 314013, "飞行任务下发失败，机场无法获取到本次飞行任务的航线，无法执行飞行任务，请稍后重试" },
        { 314014, "机场系统异常，飞行任务执行失败，请稍后重试" },
        { 314015, "机场传输精准复拍航线至飞行器失败，无法执行飞行任务，请稍后重试或重启机场后重试" },
        { 314016, "航线文件解析失败，无法执行飞行任务，请检查航线文件" },
        { 314017, "航线文件解析失败，请检查航线后再试" },
        { 314018, "飞行器RTK定位异常，无法执行飞行任务，请稍后重试或重启机场后重试" },
        { 314019, "飞行器RTK收敛失败，无法执行飞行任务，请稍后重试或重启机场后重试" },
        { 314020, "飞行器不在停机坪正中间或飞行器朝向不正确，无法执行飞行任务，请检查飞行器位置和朝向" },
        { 314021, "飞行器RTK定位异常，无法执行飞行任务，请稍后重试或重启机场后重试" },
        { 314024, "进离场航线下发失败，请稍后重试或重启机场后重试" },
        { 314025, "RTK收敛超时，用户手动取消任务" },
        { 314200, "任务失败，由于机场网络断开，飞行器已自动返航，请确保机场已连接网络后再试" },
        { 315000, "机场通信异常，请重启机场后重试" },
        { 315001, "机场通信异常，请远程开启飞机并等待1min后，再次下发任务重试" },
        { 315002, "机场通信异常，请重启机场后重试" },
        { 315003, "机场通信异常，请重启机场后重试" },
        { 315004, "任务失败，请等待两个机场都空闲后，再次下发任务重试" },
        { 315005, "机场通信异常，请重启机场后重试" },
        { 315006, "机场通信异常，请重启机场后重试" },
        { 315007, "机场通信异常，请将机场升级到最新版本或重启机场后重试" },
        { 315008, "降落机场和起飞机场标定信息不一致，请确认两个机场均链路通畅且使用了相同的网络信息标定" },
        { 315009, "机场通信异常，请重启机场后重试" },
        { 315010, "无法停止飞行任务，请稍后重试，如果仍报错请联系大疆售后" },
        { 315011, "无法停止飞行任务，请稍后重试，如果仍报错请联系大疆售后" },
        { 315012, "无法停止飞行任务，请稍后重试，如果仍报错请联系大疆售后" },
        { 315013, "飞行任务下发失败，请稍后重试，如果仍报错请联系大疆售后" },
        { 315014, "当前任务类型不支持设置返航点" },
        { 315015, "返航点设置失败，请稍后重试，如果仍报错请联系大疆售后" },
        { 315016, "飞行任务下发失败，请稍后重试，如果仍报错请联系大疆售后" },
        { 315017, "飞行任务下发失败，请稍后重试，如果仍报错请联系大疆售后" },
        { 315018, "任务失败，请等待两个机场都空闲后，再次下发任务重试" },
        { 315019, "设备部署位置不佳，无法执行蛙跳任务，请选择其它机场再试" },
        { 315050, "机场系统异常，请重启机场后重试" },
        { 315051, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315052, "机场位置未收敛，请等待一段时间后重试" },
        { 315053, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315054, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315055, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315056, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315057, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315058, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315059, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315060, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315061, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315062, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315063, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315064, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 315065, "任务失败，请重启机场并再次下发任务后重试，如果仍报错请联系大疆售后" },
        { 316001, "飞行器参数配置失败，请重启机场后重试" },
        { 316002, "飞行器参数配置失败，请重启机场后重试" },
        { 316003, "飞行器参数配置失败，请重启机场后重试" },
        { 316004, "飞行器参数配置失败，请重启机场后重试" },
        { 316005, "飞行器RTK收敛失败，无法执行飞行任务，请重启机场后重试" },
        { 316006, "任务超时，飞行器已丢失或降落时机场未开启舱盖或展开推杆，飞行器无法降落回机场，请尽快至机场部署现场检查飞行器状况" },
        { 316007, "飞行器初始化失败，请重启机场后重试" },
        { 316008, "机场获取飞行器控制权失败，无法执行飞行任务，请确认遥控器未锁定控制权" },
        { 316009, "飞行器电量低于30%，无法执行飞行任务，请充电后重试（建议电量≥50%）" },
        { 316010, "机场未检测到飞行器，无法执行飞行任务，请检查舱内是否有飞行器，机场与飞行器是否已对频，或重启机场后重试" },
        { 316011, "飞行器降落位置偏移过大，请检查飞行器是否需要现场摆正" },
        { 316012, "飞行器起飞前准备失败，无法执行飞行任务，请重启机场后重试" },
        { 316013, "飞行器起飞前准备失败，无法执行飞行任务，请重启机场后重试" },
        { 316014, "飞行器起飞前准备失败，无法执行飞行任务，请重启机场后重试" },
        { 316015, "飞行器RTK收敛位置距离机场过远，无法执行飞行任务，请重启机场后重试" },
        { 316016, "飞行器降落至机场超时，可能是机场与飞行器断连导致，请通过直播查看飞行器是否降落至舱内" },
        { 316017, "获取飞行器媒体数量超时，可能是机场与飞行器断连导致，请通过直播查看飞行器是否降落至舱内" },
        { 316018, "飞行任务执行超时，可能是机场与飞行器断连导致，请通过直播查看飞行器是否降落至舱内" },
        { 316019, "机场系统错误，无法执行飞行任务，请稍后重试" },
        { 316020, "飞行器使用的RTK信号源错误，请稍后重试" },
        { 316021, "飞行器RTK信号源检查超时，请稍后重试" },
        { 316022, "飞行器无法执行返航指令，请检查飞行器是否已开机，机场与飞行器是否已断连，请确认无以上问题后重试" },
        { 316023, "飞行器无法执行返航指令，飞行器已被B控接管，请在B控操控飞行器，或关闭B控后重试" },
        { 316024, "飞行器执行返航指令失败，请检查飞行器是否已起飞，确认飞行器已起飞后请重试" },
        { 316025, "飞行器参数配置失败，请稍后重试或重启机场后重试" },
        { 316026, "机场急停按钮被按下，无法执行飞行任务，请释放急停按钮后重试" },
        { 316027, "飞行器参数配置超时，请稍后重试或重启机场后重试" },
        { 316029, "机场急停按钮被按下，飞行器将飞往备降点降落，请立即检查飞行器是否已安全降落并将飞行器放回至机场" },
        { 316032, "获取电池数据超时，请稍后重试或重启飞行器后重试" },
        { 316033, "飞行器电池循环次数过高，为保证飞行安全，已自动终止任务，建议更换该电池" },
        { 316034, "无法起飞，飞行器固件版本与机场固件版本不匹配，为保证飞行安全请升级固件后再试" },
        { 316035, "进离场航线下发失败，请确保设备固件为最新版本后重新下发任务，如果持续报错，请联系大疆售后。" },
        { 316050, "飞行器因电量过低在舱外降落，请立即检查飞行器是否已安全降落并将飞行器放回至机场" },
        { 316051, "飞行任务异常，飞行器在舱外降落，请立即检查飞行器是否已安全降落并将飞行器放回至机场" },
        { 316052, "飞行任务异常，飞行器将飞往备降点降落，请立即检查飞行器是否已安全降落并将飞行器放回至机场" },
        { 316053, "用户已操控飞行器降落，请立即检查飞行器是否已安全降落并将飞行器放回至机场" },
        { 316100, "获取相机概要信息失败，请重试" },
        { 316101, "设置相机为单拍模式失败，请重试" },
        { 316102, "关闭相机水印失败，请重试" },
        { 316103, "设置测光模式到平均测光失败，请重试" },
        { 316104, "切换镜头到广角镜头失败，请重试" },
        { 316105, "设置相机存储照片失败，请重试" },
        { 316106, "红外变焦倍数设置失败，请重试" },
        { 316107, "照片尺寸设置4k失败，请重试" },
        { 316108, "设置照片存储格式为jpeg格式失败，请重试" },
        { 316109, "关闭相机畸变矫正失败，请重试" },
        { 316110, "打开相机机械快门失败，请重试" },
        { 316111, "设置对焦模式失败，请重试" },
        { 317001, "获取飞行器媒体文件数量失败，请重启机场后重试" },
        { 317002, "飞行器存储格式化失败，飞行器未开机、未连接或未检测到相机，请确认无以上问题后重试，或重启飞行器后重试" },
        { 317003, "飞行器存储格式化失败，请重启飞行器后重试" },
        { 317004, "机场媒体文件格式化失败，请稍后重试或重启机场后重试" },
        { 317005, "飞行器结束录像失败，本次飞行任务的媒体文件可能无法上传" },
        { 317006, "无法格式化，请等待当前飞行器媒体文件下载完成后再试" },
        { 317007, "获取媒体文件数量失败，请稍后重试，如本架次任务有媒体文件且持续报错可联系大疆售后" },
        { 319001, "机场作业中或设备异常反馈上传日志中，无法执行飞行任务，请等待当前飞行任务或操作执行完成后重试" },
        { 319002, "机场系统运行异常，请重启机场后重试" },
        { 319003, "机场系统运行异常，请重新下发任务" },
        { 319004, "飞行任务执行超时，已自动终止本次飞行任务" },
        { 319005, "云端与机场通信异常，无法执行飞行任务" },
        { 319006, "取消飞行任务失败，飞行任务已经在执行中" },
        { 319007, "修改飞行任务失败，飞行任务已经在执行中" },
        { 319008, "机场时间与云端时间不同步，机场无法执行飞行任务" },
        { 319009, "飞行任务下发失败，请稍后重试或重启机场后重试" },
        { 319010, "机场固件版本过低，无法执行飞行任务，请升级机场固件为最新版本后重试" },
        { 319015, "机场正在初始化中，无法执行飞行任务，请等待机场初始化完成后重试" },
        { 319016, "机场正在执行其他飞行任务，无法执行本次飞行任务" },
        { 319017, "机场正在处理上次飞行任务媒体文件，无法执行本次飞行任务，请稍后重试" },
        { 319018, "机场正在自动导出日志中（设备异常反馈），无法执行飞行任务，请稍后重试" },
        { 319019, "机场正在拉取日志中（设备异常反馈），无法执行飞行任务，请稍后重试" },
        { 319020, "航线中断失败，请稍后重试" },
        { 319021, "退出远程控制失败，请稍后重试" },
        { 319022, "指点飞行失败，请稍后重试" },
        { 319023, "指点飞行停止失败，请稍后重试" },
        { 319024, "一键起飞失败，请稍后重试" },
        { 319025, "机场未准备完成，无法执行云端下发的飞行任务，请稍后重试" },
        { 319026, "飞行器电池电量低于用户设置的任务开始执行的电量，请等待充电完成后再执行飞行任务" },
        { 319027, "机场或飞行器剩余存储容量过低，无法执行飞行任务，请等待媒体文件上传，机场和飞行器存储容量释放后再执行飞行任务" },
        { 319028, "正在更新自定义飞行区" },
        { 319029, "正在更新离线地图" },
        { 319030, "操作失败，无飞行器控制权" },
        { 319031, "控制权异常，请刷新重试" },
        { 319032, "指点飞行失败，请稍后重试" },
        { 319033, "虚拟摇杆操作失败，请稍后重试" },
        { 319034, "虚拟摇杆操作失败，请稍后重试" },
        { 319035, "急停失败，请稍后重试" },
        { 319036, "设备远程调试中，请稍后重试" },
        { 319037, "设备本地调试中，请稍后重试" },
        { 319038, "设备正在升级，请稍后重试" },
        { 319042, "航线恢复失败，请稍后重试" },
        { 319043, "取消返航失败，请稍后重试" },
        { 319044, "航线任务已结束，无法恢复" },
        { 319045, "急停成功，请重新按键操作" },
        { 319046, "无法暂停航线，飞行器尚未进入航线或已退出航线" },
        { 319999, "机场系统运行异常，请重启机场后重试" },
        { 321000, "航线执行异常，请稍后重试或重启机场后重试" },
        { 321004, "航线文件解析失败，无法执行飞行任务，请检查航线文件" },
        { 321005, "航线缺少断点信息，机场无法执行飞行任务" },
        { 321257, "飞行任务已在执行中，请勿重复执行" },
        { 321258, "飞行任务无法终止，请检查飞行器状态" },
        { 321259, "飞行任务未开始执行，无法终止飞行任务" },
        { 321260, "飞行任务未开始执行，无法中断飞行任务" },
        { 321513, "航线规划高度已超过飞行器限高，机场无法执行飞行任务" },
        { 321514, "任务失败，起点或终点位于限远区域的缓冲区内或超过了限远距离" },
        { 321515, "航线穿过限飞区，机场无法执行飞行任务" },
        { 321516, "飞行器飞行高度过低，飞行任务执行被终止" },
        { 321517, "飞行器触发避障，飞行任务执行被终止。为保证飞行安全，请勿用当前航线执行断点续飞任务" },
        { 321519, "飞行器接近限飞区或限远距离自动返航，无法完成航线飞行" },
        { 321523, "飞行器起飞失败，请稍后重试，如果仍报错请联系大疆售后。" },
        { 321524, "飞行器起飞前准备失败，可能是飞行器无法定位或档位错误导致，请检查飞行器状态" },
        { 321528, "触碰自定义飞行区边界，航线任务已暂停" },
        { 321529, "目标点位于禁飞区域或者障碍物内，无法到达，航线任务已暂停，请重新规划后再试" },
        { 321530, "飞行器飞行航线过程中轨迹规划失败，航线任务已暂停" },
        { 321531, "进离场航线执行失败，请联系大疆售后。" },
        { 321532, "进离场航线执行失败，请联系大疆售后。" },
        { 321533, "进离场航线执行失败，请联系大疆售后。" },
        { 321769, "飞行器卫星定位信号差，无法执行飞行任务，请重启机场后重试" },
        { 321770, "飞行器挡位错误，无法执行飞行任务，请重启机场后重试" },
        { 321771, "飞行器返航点未设置，无法执行飞行任务，请重启机场后重试" },
        { 321772, "飞行器电量低于30%，无法执行飞行任务，请充电后重试（建议电量≥50%）" },
        { 321773, "飞行器执行飞行任务过程中低电量返航，无法完成航线飞行" },
        { 321775, "飞行器航线飞行过程中失联，无法完成航线飞行" },
        { 321776, "飞行器RTK收敛失败，无法执行飞行任务，请重启机场后重试" },
        { 321777, "飞行器未悬停，无法开始执行飞行任务" },
        { 321778, "用户使用B控操控飞行器起桨，机场无法执行飞行任务" },
        { 321784, "任务过程中遇到大风紧急返航" },
        { 322281, "任务失败，机场执行飞行任务过程被手动打断或异常终止" },
        { 322282, "机场执行飞行任务过程中被中断，飞行器被云端用户或遥控器接管" },
        { 322283, "机场执行飞行任务过程中被用户触发返航，无法完成航线飞行" },
        { 322539, "航线的断点信息错误，机场无法执行飞行任务" },
        { 322563, "航线轨迹生成失败，请检查飞行器视觉镜头是否存在脏污或重启飞行器后再试，如果仍报错请联系大疆售后" },
        { 324012, "日志压缩过程超时，所选日志过多，请减少选择的日志后重试" },
        { 324013, "设备日志列表获取失败，请稍后重试" },
        { 324014, "设备日志列表为空，请刷新页面或重启机场后重试" },
        { 324015, "飞行器已关机或未连接，无法获取日志列表，请确认飞行器在舱内，通过远程调试将飞行器开机后重试" },
        { 324016, "机场存储空间不足，日志压缩失败，请清理机场存储空间或稍后重试" },
        { 324017, "日志压缩失败，无法获取所选飞行器日志，请刷新页面或重启机场后重试" },
        { 324018, "日志文件拉取失败，导致本次设备异常反馈上传失败，请稍后重试或重启机场后重试" },
        { 324019, "因机场网络异常，日志上传失败，请稍后重试。如果连续多次出现该问题，请联系代理商或大疆售后进行网络排障" },
        { 324021, "因机场断电或重启导致日志导出中断，日志导出失败，请稍后重试" },
        { 324030, "因机场网络异常、飞行器图传链路异常等原因，媒体文件暂时无法上传或文件已上传但云端读取失败" },
        { 325001, "云端下发命令不符合格式要求，设备无法执行" },
        { 325003, "指令响应失败，请重试" },
        { 325004, "设备端命令请求已超时，请重试" },
        { 325005, "当前机场无法响应任务，请稍后重试" },
        { 325006, "当前机场启动检查中，请稍后重试" },
        { 325007, "当前机场执行作业任务中，请稍后重试" },
        { 325008, "当前机场处理作业任务结果中，请稍后重试" },
        { 325009, "当前机场执行远程日志导出中，请稍后重试" },
        { 325010, "当前机场更新自定义飞行区中，请稍后重试" },
        { 325011, "当前机场更新离线地图中，请稍后重试" },
        { 325012, "当前飞机未连接，请稍后重试" },
        { 326002, "飞行器未安装DJICellualr模块" },
        { 326003, "飞行器DJICellualr模块中未安装SIM卡" },
        { 326004, "飞行器DJICellualr模块需要强制升级，否则无法使用" },
        { 326005, "操作失败，增强图传无法建立连接，请检查4G信号强度，或咨询运营商查询套餐流量和APN设置" },
        { 326006, "增强图传开关切换失败，请稍后重试" },
        { 326008, "机场未安装DJICellualr模块" },
        { 326009, "机场DJICellualr模块中未安装SIM卡" },
        { 326010, "机场DJICellualr模块需要强制升级，否则无法使用" },
        { 326103, "当前eSIM正在激活中，请稍后再试" },
        { 326104, "当前eSIM正在切换运营商中，请稍后再试" },
        { 326105, "DJI增强图传模块正在切换模式中，请稍后再试" },
        { 326106, "DJI增强图传模块异常，请重启设备后再试，如果仍报错请联系大疆售后" },
        { 326107, "请在设备管理>机场>设备运维中激活DJI增强图传模块的eSIM或插入SIM卡后再试" },
        { 327000, "参数设置失败，请稍后重试" },
        { 327001, "参数设置失败，请稍后重试" },
        { 327002, "获取控制权失败，请稍后重试" },
        { 327003, "获取控制权失败，请稍后重试" },
        { 327004, "画面拖动失败，请重试" },
        { 327005, "双击画面归中失败" },
        { 327006, "拍照失败" },
        { 327007, "开始录像失败" },
        { 327008, "停止录像失败" },
        { 327009, "切换相机模式失败" },
        { 327010, "ZOOM相机变焦失败" },
        { 327011, "IR相机变焦失败" },
        { 327012, "获取控制权失败，请稍后重试" },
        { 327013, "参数设置失败，请稍后重试" },
        { 327014, "云台已达限位" },
        { 327015, "直播启动失败，建议刷新直播或重新打开设备小窗" },
        { 327016, "失联动作设置失败，请重试" },
        { 327017, "指点飞行高度设置失败，请重试" },
        { 327018, "指点飞行模式切换失败，请重试" },
        { 327019, "当前状态无法看向标注点" },
        { 327020, "全景拍照停止命令超时" },
        { 327050, "当前设备状态不支持播放音频" },
        { 327051, "下载音频文件失败" },
        { 327052, "喊话器处理模式切换失败" },
        { 327053, "上传音频文件失败" },
        { 327054, "播放音频失败" },
        { 327055, "设置工作模式失败" },
        { 327056, "上传文本失败" },
        { 327057, "停止播放失败" },
        { 327058, "设置播放模式失败" },
        { 327059, "设置音量失败" },
        { 327060, "设置控件值失败" },
        { 327061, "发送文本值失败" },
        { 327062, "切换系统语言失败" },
        { 327063, "获取设备功能列表失败" },
        { 327064, "获取设备配置文件失败" },
        { 327065, "获取设备图片文件失败" },
        { 327066, "设备文件压缩失败" },
        { 327067, "设备文件上传失败" },
        { 327068, "上传音频文件失败，md5校验失败" },
        { 327069, "上传音频文件失败" },
        { 327070, "上传音频文件失败，异常终止" },
        { 327071, "上传TTS文本失败，md5校验失败" },
        { 327072, "上传TTS文本失败" },
        { 327073, "上传TTS文本失败，异常终止" },
        { 327074, "喊话器重播失败" },
        { 327075, "喊话器编码失败" },
        { 327201, "全景拍照失败" },
        { 327202, "全景拍摄终止" },
        { 327203, "当前设备不支持全景拍照" },
        { 327204, "系统繁忙，无法全景拍照" },
        { 327205, "请求失败，无法全景拍照" },
        { 327206, "飞机未起飞，无法开始全景拍摄" },
        { 327207, "控制权获取失败，全景拍摄终止" },
        { 327208, "未知相机错误，无法开始全景拍摄" },
        { 327209, "相机超时，全景拍摄终止" },
        { 327210, "无法全景拍照" },
        { 327211, "存储空间不足，全景拍摄终止" },
        { 327212, "飞机运动中，无法开始全景拍摄" },
        { 327213, "云台运动中，无法开始全景拍摄" },
        { 327214, "用户操作摇杆，全景拍摄终止" },
        { 327215, "碰到限飞区，全景拍摄终止" },
        { 327216, "触发距离限制，全景拍摄终止" },
        { 327217, "云台受阻，全景拍摄终止" },
        { 327218, "拍照失败，全景拍摄终止" },
        { 327219, "全景图片拼接失败" },
        { 327220, "加载标定参数失败，全景拍摄终止" },
        { 327221, "调整相机参数失败，全景拍摄终止" },
        { 327500, "飞行器镜头除雾失败，请稍后重试" },
        { 328051, "飞机未完成实名登记，请连接遥控器，按照指引完成、实名登记后飞行" },
        { 328052, "飞机实名登记状态已注销，请连接遥控器，按照指引完成实名登记后飞行" },
        { 336000, "指点飞行命令发送失败，请重试" },
        { 336001, "飞行器数据异常，无法响应指令" },
        { 336002, "飞行器GPS信号差" },
        { 336003, "飞行器定位失效，无法响应指令" },
        { 336004, "指点飞行自主规划失败" },
        { 336005, "飞行器返航点未更新" },
        { 336006, "飞行器已失联，已退出指点飞行" },
        { 336017, "飞行器电量不足以完成当前任务" },
        { 336018, "已切换飞行器规划模式" },
        { 336019, "指点飞行因限高自动调整飞行高度" },
        { 336513, "目标点在禁飞区内" },
        { 336514, "目标点超出飞行器限远" },
        { 336515, "目标点在禁飞区内" },
        { 336516, "目标点超出飞行器限高" },
        { 336517, "目标点超出飞行器限低" },
        { 337025, "飞行器无法起飞" },
        { 337026, "目标点异常，请重试" },
        { 337027, "飞行器速度设置异常，请重试" },
        { 337028, "飞行器版本异常，请检查飞行器版本" },
        { 337029, "飞行器无法响应当前任务，请稍后重试" },
        { 337030, "指令飞行安全离场高过低" },
        { 337537, "已触碰禁飞区" },
        { 337538, "已触碰飞行器限远" },
        { 337539, "已触碰禁飞区" },
        { 337540, "已触碰飞行器限高或限高区" },
        { 337541, "已触碰飞行器限低" },
        { 337542, "飞行器起飞失败，请重试" },
        { 337543, "目标点可能在障碍物内，请检查周边环境" },
        { 337544, "检测到障碍物，请检查周边环境" },
        { 337545, "飞行器规划异常，请重试" },
        { 337546, "已触碰自定义飞行区边界" },
        { 338001, "飞行器通信异常，无法执行飞行任务，请重启飞行器与机场后重试" },
        { 338002, "飞行器通信异常，无法执行飞行任务，请重启飞行器与机场后重试" },
        { 338003, "飞行器通信异常，无法执行飞行任务，请重启飞行器与机场后重试" },
        { 338004, "飞行器通信异常，无法执行飞行任务，请重启飞行器与机场后重试" },
        { 338005, "起飞机场与降落机场部署距离超出限制，无法执行飞行任务，请选择两个部署距离不超过15km的机场执行任务" },
        { 338006, "无法执行飞行任务，请检查降落机场是否已申请解禁证书、是否位于自定义禁飞区或是否位于自定义飞行区外" },
        { 338007, "目标降落机场部署突破限高区限高，无法执行任务，请申请解禁证书后再试" },
        { 338008, "目标降落机场部署突破飞行器设置的限高，无法执行任务，请调整限高后重试" },
        { 338009, "飞行器GPS定位信号差，无法执行任务，请重启飞行器后重试" },
        { 338010, "飞行器定位失效，无法执行任务，请重启飞行器后重试" },
        { 338011, "任务失败，目标机场处于地理鸟笼作业区域外，请重新规划任务后再试" },
        { 338017, "飞行器数据更新失败，无法执行任务，请重启飞行器后重试" },
        { 338018, "飞行器数据更新失败，无法执行任务，请重启飞行器后重试" },
        { 338019, "飞行器到目标机场的返航路线正在规划中，无法执行任务，请重启飞行器后重试" },
        { 338020, "飞行器无法根据规划的路径到达目标降落机场，无法执行任务，请重新选择降落机场后再试" },
        { 338021, "飞行器当前电量不足以到达目标降落机场，无法执行任务，请给飞行器充电后重试" },
        { 338049, "响应遥控器杆量，已退出指点飞行" },
        { 338050, "响应终止指令，已退出指点飞行" },
        { 338051, "飞行器低电量返航，已退出指点飞行" },
        { 338052, "飞行器低电量降落，已退出指点飞行" },
        { 338053, "附近有载人机，已退出指点飞行" },
        { 338054, "响应其他高优先级任务，已退出指点飞行" },
        { 338255, "飞行器通信异常，无法执行飞行任务，请重启飞行器与机场后重试" },
        { 386535, "航线执行异常，请稍后重试或重启机场后重试" },
        { 513002, "直播失败，相机不存在或相机类型错误" },
        { 513003, "相机已经在直播中，请勿重复开启直播" },
        { 513005, "直播失败，直播参数（清晰度）设置错误" },
        { 513006, "直播启动失败，请刷新重试" },
        { 513008, "直播失败，设备端图传数据异常" },
        { 513010, "直播失败，设备无法联网" },
        { 513011, "操作失败，设备未开启直播" },
        { 513012, "操作失败，设备已在直播中，不支持切换镜头" },
        { 513013, "直播失败，直播使用的视频传输协议不支持" },
        { 513014, "直播失败，直播参数错误或者不完整" },
        { 513015, "直播异常，网络卡顿,请刷新后重试" },
        { 513016, "直播异常，视频解码失败" },
        { 513017, "直播已暂停，请等待当前飞行器媒体文件下载完成后再试" },
        { 513099, "直播失败，请稍后重试" },
        { 514100, "机场运行异常，请重启机场后重试" },
        { 514101, "推杆闭合失败，请检查停机坪上是否存在异物，飞行器方向是否放反，或重启机场后重试" },
        { 514102, "推杆展开失败，请检查停机坪上是否存在异物，或重启机场后重试" },
        { 514103, "飞行器电量低于30%，无法执行飞行任务，请充电后重试（建议电量≥50%）" },
        { 514104, "飞行器电池开始充电失败，请重启机场后重试" },
        { 514105, "飞行器电池停止充电失败，请重启机场后重试" },
        { 514106, "飞行器电源控制异常，请重启机场后重试" },
        { 514107, "舱盖开启失败，请检查舱盖周围是否存在异物，或重启机场后重试" },
        { 514108, "舱盖关闭失败，请检查舱盖周围是否存在异物，或重启机场后重试" },
        { 514109, "飞行器开机失败，请检查飞行器是否在舱和飞机电量是否正常，或重启机场后重试" },
        { 514110, "飞行器关机失败，请重启机场后重试" },
        { 514111, "飞行器慢转收桨控制异常，请重启机场后重试" },
        { 514112, "飞行器慢转收桨控制异常，请重启机场后重试" },
        { 514113, "机场推杆与飞行器无法连接，请检查飞行器是否在舱内，推杆闭合时是否被卡住，充电连接器是否脏污或损坏" },
        { 514114, "获取飞行器电源状态失败，请重启机场后重试" },
        { 514116, "无法执行当前操作，机场正在执行其他控制指令，请稍后重试" },
        { 514117, "舱盖开启或关闭未到位，请重启机场后重试" },
        { 514118, "推杆展开或闭合未到位，请重启机场后重试" },
        { 514120, "机场与飞行器断连，请重启机场后重试或重新对频" },
        { 514121, "机场急停按钮被按下，请释放急停按钮" },
        { 514122, "获取飞行器充电状态失败，请重启机场后重试" },
        { 514123, "飞行器电池电量过低无法开机" },
        { 514124, "获取飞行器电池信息失败，无法执行飞行任务，请重启机场后重试" },
        { 514125, "飞行器电池电量已接近满电状态，无法开始充电，请使用至95%以下再进行充电" },
        { 514134, "雨量过大，机场无法执行飞行任务，请稍后重试" },
        { 514135, "风速过大，机场无法执行飞行任务，请稍后重试" },
        { 514136, "机场供电断开，机场无法执行飞行任务，请恢复机场供电后重试" },
        { 514137, "环境温度过低于-20℃(-4°F)，机场无法执行飞行任务，请稍后重试" },
        { 514138, "飞行器电池正在保养中，机场无法执行飞行任务，请等待保养结束后重试" },
        { 514139, "飞行器电池无法执行保养指令，飞行器电池无需保养" },
        { 514140, "飞行器电池无法执行保养指令，飞行器电池无需保养" },
        { 514141, "机场系统运行异常，请重启机场后重试" },
        { 514142, "飞行器起飞前，机场推杆与飞行器无法连接，请检查飞行器是否在舱内，推杆闭合时是否被卡住，充电连接器是否脏污或损坏" },
        { 514143, "推杆未闭合或闭合不到位，请稍后重试或重启机场后重试" },
        { 514144, "舱盖未关闭或关闭不到位，请稍后重试或重启机场后重试" },
        { 514145, "机场处于现场调试中，无法执行当前操作或执行飞行任务，请断开遥控器和机场的数据线连接后重试" },
        { 514146, "机场处于远程调试中，无法执行飞行任务，请退出远程调试后重试" },
        { 514147, "设备升级中，无法进行远程调试或执行飞行任务，请等待升级完成后重试" },
        { 514148, "机场已经在作业中，无法进行远程调试或再次执行飞行任务，请等待当前任务执行完成后重试" },
        { 514149, "机场系统运行异常，无法执行飞行任务，请重启机场后重试" },
        { 514150, "设备重启中，无法执行飞行任务，请等待重启完成后重试" },
        { 514151, "设备升级中，无法执行设备重启指令，请等待升级完成后重试" },
        { 514153, "机场已退出远程调试模式，无法执行当前操作" },
        { 514154, "获取内循环出风口温度失败，请稍后再试" },
        { 514156, "飞机不在舱内，请立即检查飞行器是否已安全降落并将飞行器放回至机场" },
        { 514157, "执行开机失败，无线充电线圈业务繁忙，请重启机场后再试复" },
        { 514158, "无法起飞，机场RTK业务异常，请重启机场后再试" },
        { 514159, "任务失败，降落机场检测到飞行器，请确保降落机场没有飞行器后再试" },
        { 514162, "飞行器和机场连接失败，请关闭机场舱盖或重启机场后再试" },
        { 514163, "电池功能异常，请确保飞行器电池插入到位或重启飞行器后再试" },
        { 514164, "设备重启失败，请稍后重试，如果仍报错请联系大疆售后" },
        { 514165, "设备重启失败，请稍后重试，如果仍报错请联系大疆售后" },
        { 514170, "机场系统初始化中，无法执行当前操作或指令，请等待机场系统初始化完成后重试" },
        { 514171, "云端下发给机场的命令不符合格式要求，机场无法执行" },
        { 514172, "飞行器无法关机，蓝牙连接状态为未连接，请尝试重启飞行器和机场，或去现场重新对频飞行器与机场后再试" },
        { 514173, "由于天气原因（环境温度低于5度并且降雨大于等于中雨），可能导致桨叶结冰影响作业安全，暂无法执行任务" },
        { 514174, "飞行器充电失败，机场舱盖开启或关闭未到位，请关闭舱盖后再试" },
        { 514180, "停止空调制冷或停止空调制热失败，请稍后重试" },
        { 514181, "开启空调制冷失败，请稍后重试" },
        { 514182, "开启空调制热失败，请稍后重试" },
        { 514183, "开启空调除湿失败，请稍后重试" },
        { 514184, "当前温度低于0℃（32°F），无法开启空调制冷" },
        { 514185, "当前温度高于45℃（115°F），无法开启空调制热" },
        { 514300, "网关异常" },
        { 514301, "请求超时，连接断开" },
        { 514302, "网络证书异常，连接失败" },
        { 514303, "网络异常，连接断开" },
        { 514304, "请求被拒，连接失败" }
    };
}