using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using MDCSToolBox.Clumsy.Movements;
using Nancy;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SimpleLite;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using SimpleLite.CADTools;
using SimpleLite.Props;
using SimpleLite.UI;
using SimpleCore;
using SimpleCore.Library;
using SimpleCore.PropType;
using StandardScene.Chained;
using StandardScene.Charge;
using StandardScene.Model;
using StandardScene.Utils;
using static StandardScene.Chained.ChainedDeliveryMission;
using Map = StandardScene.Model.Map;
using Nancy.Session;
using StandardScene.InterLock;

namespace StandardScene
{
    /// <summary>
    /// 【过渡期遗留】老平台 Nancy HTTP 接口（40+ 端点）。导航耦合极弱：仅二维码 QrMap（数据仍存
    /// 本类静态字段，由 scene.qrlidar 插件的 SyncQrMap 工具写入）与 getLidarMap。
    /// 拆分计划 §4.7：暂留 Core 维持现场兼容，后续逐步迁往 SimpleLite 的 EmbedIO 接口（MIGU-API），
    /// 新功能请勿在此追加端点。
    /// </summary>
    public class ApiController : NancyModule
    {
        private static readonly HttpClient SharedHttpClient = new HttpClient();
        private static readonly string ApiToken = Environment.GetEnvironmentVariable("STANDARDSCENE_API_TOKEN");
        private static List<TaskRequest> _taskRequests = new List<TaskRequest>();
        public static MyDict<int, (float, float, float)> QrMap =
            new MyDict<int, (float, float, float)>();
        public static string QrMapJson;

        private string GetMethods(Type baseClassType)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var derivedTypes = assembly.GetTypes()
                .Where(t => t.IsSubclassOf(baseClassType));

            var classMethodsDictionary = new Dictionary<string, List<MethodInfoDetails>>();

            foreach (var type in derivedTypes)
            {
                // old-school MethodMember
                var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                    .Where(m => m.GetCustomAttribute<MethodMember>() != null && m.GetCustomAttribute<NoReflectionApi>() == null)
                    .Select(m =>
                    {
                        var attr = m.GetCustomAttribute<MethodMember>();
                        var ret = new MethodInfoDetails() { MethodName = m.Name };
                        var nameField = attr.Name;
                        if (nameField != null) ret.ButtonName = nameField;
                        var descField = attr.Description;
                        if (descField != null) ret.ButtonDescription = descField;
                        return ret;
                    })
                    .ToList();

                // Methods with parameters
                var paramMethods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                    .Where(m => m.GetCustomAttribute<ReflectionApiWithParameter>() != null)
                    .Select(m =>
                    {
                        var attr = m.GetCustomAttribute<ReflectionApiWithParameter>();
                        var ret = new MethodInfoDetails() { MethodName = m.Name };
                        var nameField = attr.name;
                        if (nameField != null) ret.ButtonName = nameField;
                        var descField = attr.desc;
                        if (descField != null) ret.ButtonDescription = descField;
                        var hintField = attr.Hint;
                        if (hintField != null) ret.ParamsHint = hintField;
                        ret.ParamsList = m.GetParameters().Select(mp => new ParamInfo(mp.Name, mp.ParameterType)).ToList();
                        return ret;
                    })
                    .ToList();

                classMethodsDictionary[type.Name] = methods.Concat(paramMethods).ToList();
            }

            return JsonConvert.SerializeObject(
                new { Success = true, Code = 200, Data = classMethodsDictionary, Message = "Success" },
                Formatting.Indented);
        }

        //获取指定class所有方法的字典
        private Dictionary<string, List<MethodInfoDetails>> GetTypeMethods(Type type)
        {
            string[] shieldMethodButtonNames = new[]
                { "导出小车日志", "前往站点", "重启通信进程", "手动下发指令", "计划重启", "抛出中断", "放行", "显示调试信息", "给逃逸路径的初始化","返厂检修" };
            var classMethodsDictionary = new Dictionary<string, List<MethodInfoDetails>>();
            // old-school MethodMember
            var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Where(m => m.GetCustomAttribute<MethodMember>() != null && m.GetCustomAttribute<NoReflectionApi>() == null)
                .Where(m => !shieldMethodButtonNames.Any(n => m.GetCustomAttribute<MethodMember>().Name.Contains(n)))
                .Select(m =>
                {
                    var attr = m.GetCustomAttribute<MethodMember>();
                    var ret = new MethodInfoDetails() { MethodName = m.Name };
                    var nameField = attr.Name;
                    if (nameField != null) ret.ButtonName = nameField;
                    var descField = attr.Description;
                    if (descField != null) ret.ButtonDescription = descField;
                    return ret;
                })
                .ToList();

            // Methods with parameters
            var paramMethods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Where(m => m.GetCustomAttribute<ReflectionApiWithParameter>() != null)
                .Select(m =>
                {
                    var attr = m.GetCustomAttribute<ReflectionApiWithParameter>();
                    var ret = new MethodInfoDetails() { MethodName = m.Name };
                    var nameField = attr.name;
                    if (nameField != null) ret.ButtonName = nameField;
                    var descField = attr.desc;
                    if (descField != null) ret.ButtonDescription = descField;
                    var hintField = attr.Hint;
                    if (hintField != null) ret.ParamsHint = hintField;
                    ret.ParamsList = m.GetParameters().Select(mp => new ParamInfo(mp.Name, mp.ParameterType)).ToList();
                    return ret;
                })
                .ToList();

            classMethodsDictionary[type.Name] = methods.Concat(paramMethods).ToList();

            return classMethodsDictionary;
        }

        /// <summary>
        /// 反射调用白名单：仅允许显式标注为可暴露的方法被 HTTP 反射调用，
        /// 与 GetMethods 的暴露口径一致，避免“按名调用任意 public 方法”的远程执行风险。
        /// </summary>
        private static bool IsReflectionInvokable(MethodInfo methodInfo)
        {
            if (methodInfo == null) return false;
            if (methodInfo.GetCustomAttribute<NoReflectionApi>() != null) return false;
            return methodInfo.GetCustomAttribute<MethodMember>() != null
                || methodInfo.GetCustomAttribute<ReflectionApiWithParameter>() != null;
        }

        private static string ReflectionForbidden(object id, string method)
        {
            return JsonConvert.SerializeObject(new
            {
                Success = false,
                Code = 403,
                Data = "null",
                Message = $"method {method} of {id} is not exposed for reflection invocation"
            }, Formatting.Indented);
        }

        private bool IsAuthorized()
        {
            if (string.IsNullOrEmpty(ApiToken)) return true;
            try
            {
                var q = ((DynamicDictionary)Request.Query).ToDictionary();
                return q.TryGetValue("token", out var t) && t != null && t.ToString() == ApiToken;
            }
            catch
            {
                return false;
            }
        }

        private static string Unauthorized()
        {
            return JsonConvert.SerializeObject(new
            {
                Success = false,
                Code = 401,
                Data = "null",
                Message = "unauthorized: missing or invalid api token"
            }, Formatting.Indented);
        }

        private dynamic CarReflectionExecute(dynamic parameters)
        {
            try
            {
                if (!IsAuthorized()) return Unauthorized();
                var car = SimpleLib.GetCar((int)parameters.id);
                if (car == null)
                    return JsonConvert.SerializeObject(
                        new { Success = false, Code = 500, Data = "null", Message = $"no car of id {parameters.id}" }, Formatting.Indented);
                var queryParams = ((DynamicDictionary)Request.Query).ToDictionary();
                queryParams.Remove("token");
                MethodInfo methodInfo = null;
                if (queryParams.Keys.Count == 0)
                    methodInfo = car.GetType().GetMethod((string)parameters.method, new Type[] { });
                else
                    methodInfo = car.GetType().GetMethod((string)parameters.method);
                if (methodInfo == null)
                    return JsonConvert.SerializeObject(
                        new { Success = false, Code = 500, Data = "null", Message = $"car {parameters.id} has no method {parameters.method}" }, Formatting.Indented);
                if (!IsReflectionInvokable(methodInfo))
                    return ReflectionForbidden(parameters.id, (string)parameters.method);
                return ExecuteMethod(methodInfo, car, queryParams);
            }
            catch (Exception ex)
            {
                return JsonConvert.SerializeObject(
                    new { Success = false, Code = 500, Data = "null", Message = ex.Message }, Formatting.Indented);
            }
        }

        private dynamic MissionReflectionExecute(dynamic parameters)
        {
            try
            {
                if (!IsAuthorized()) return Unauthorized();
                var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
                if (mission == null)
                    return JsonConvert.SerializeObject(
                        new { Success = false, Code = 500, Data = "null", Message = $"no mission of id {parameters.id}" }, Formatting.Indented);
                var methodInfo = mission.GetType().GetMethod((string)parameters.method);
                if (methodInfo == null)
                    return JsonConvert.SerializeObject(
                        new { Success = false, Code = 500, Data = "null", Message = $"mission {parameters.id} has no method {parameters.method}" }, Formatting.Indented);
                var queryParams = ((DynamicDictionary)Request.Query).ToDictionary();
                queryParams.Remove("token");
                if (!IsReflectionInvokable(methodInfo))
                    return ReflectionForbidden(parameters.id, (string)parameters.method);
                return ExecuteMethod(methodInfo, mission, queryParams);
            }
            catch (Exception ex)
            {
                return JsonConvert.SerializeObject(
                    new { Success = false, Code = 500, Data = "null", Message = ex.Message }, Formatting.Indented);
            }
        }

        private string ExecuteMethod(MethodInfo methodInfo, object instance, Dictionary<string, object> inputs)
        {
            var methodParam = methodInfo.GetParameters();
            List<object> paramList = new List<object>();
            if (methodParam.Length == 0)
            {
                methodInfo.Invoke(instance, null);
            }
            else
            {
                if (inputs.Count != methodParam.Length)
                {
                    return JsonConvert.SerializeObject(
                        new
                        {
                            Success = false,
                            Code = 500,
                            Data = "null",
                            Message = $"method need {methodParam.Length} params , but {inputs.Count}"
                        }, Formatting.Indented);
                }
                for (int i = 0; i < methodParam.Length; i++)
                {
                    paramList.Add(Convert.ChangeType(inputs[methodParam[i].Name], methodParam[i].ParameterType));
                }
                var actualParam = paramList.ToArray();
                methodInfo.Invoke(instance, actualParam);
            }

            return JsonConvert.SerializeObject(
                new { Success = true, Code = 200, Data = "null", Message = "Success" }, Formatting.Indented);
        }


        public ApiController()
        {
            After.AddItemToEndOfPipeline(ctx =>
            {
                ctx.Response.WithHeader("Access-Control-Allow-Origin", "*")
                    .WithHeader("Access-Control-Allow-Methods", "POST,GET")
                    .WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-Type");
            });

            // 反射接口共识：
            // 所有simple的调度对象（包括车、进程）只有id是全局唯一的。
            // 所有simple的调度对象可能有不同的class，class相同的可能有不同的name（name并非全局唯一）。
            // 所有simple的调度对象都有属性（field）、状态（status）、动作（methodMember）。
            // 属性是可读可写的字典（用户设定属性，并保存属性作为运行配置）。状态是只读的字典。动作是函数成员。
            // 反射接口全部返回json字符串，包括success和result两个字段。
            // success为true或者false，分别表示请求成功或失败。
            // result为返回内容。success为false时，result是报错内容。

            // 返回className
            Get("/car_reflection/get_type/{id}", parameters =>
            {
                try
                {
                    var car = SimpleLib.GetCar((int)parameters.id);
                    if (car == null)
                        return JsonConvert.SerializeObject(
                            new
                            {
                                Success = false,
                                Code = 500,
                                Data = "null",
                                Message = $"no car of id {parameters.id}"
                            }, Formatting.Indented);
                    return JsonConvert.SerializeObject(
                        new { Success = true, Code = 200, Data = car.GetType().Name, Message = "Success" },
                        Formatting.Indented);
                }
                catch (Exception ex)
                {
                    return JsonConvert.SerializeObject(
                        new { success = false, Code = 500, Data = "null", Message = ex.Message }, Formatting.Indented);
                }
            });
            Get("/car_reflection/get_methods/{id}", parameters =>
            {
                try
                {
                    var car = SimpleLib.GetCar((int)parameters.id);
                    if (car == null)
                        return JsonConvert.SerializeObject(
                            new
                            {
                                Success = false,
                                Code = 500,
                                Data = "null",
                                Message = $"no car of id {parameters.id}"
                            }, Formatting.Indented);

                    var classMethodsDictionary = GetTypeMethods(car.GetType());
                    if (classMethodsDictionary == null)
                    {
                        return JsonConvert.SerializeObject(new
                        {
                            Success = false,
                            Code = 500,
                            Data = "null",
                            Message = $"未匹配到id：[{parameters.id}] 的车辆"
                        },
                        Formatting.Indented);
                    }
                    return JsonConvert.SerializeObject(new
                    {
                        Success = true,
                        Code = 200,
                        Data = classMethodsDictionary.Values.FirstOrDefault(),
                        Message = "Success"
                    },
                    Formatting.Indented);

                }
                catch (Exception e)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        Success = false,
                        Code = 500,
                        Data = "null",
                        Message = e.Message
                    },
                     Formatting.Indented);
                }
            });

            // 返回每种className对应有哪些动作
            Get("/car_reflection/get_type_methods", _ => GetMethods(typeof(GhostCar)));

            // 执行动作（支持任意数量参数）；执行类操作同时提供 POST 语义化入口，保留 GET 兼容旧前端
            Get("/car_reflection/execute/{id}/{method}", parameters => CarReflectionExecute(parameters));
            Post("/car_reflection/execute/{id}/{method}", parameters => CarReflectionExecute(parameters));

            // 返回(id, name, className)的列表
            Get("/mission_reflection/get_mission_list", _ =>
                JsonConvert.SerializeObject(new
                {
                    Success = true,
                    Code = 200,
                    Data = SimpleProject.proj.Missions.Select(mm =>
                    {
                        var mType = (MissionType)mm.GetType().GetCustomAttribute(typeof(MissionType));
                        return new { id = mm.id, name = mm.name, typeName = mType.Name, state = mm.status.status };
                    }),
                    Message = "Success"
                }, Formatting.Indented));

            Get("/mission_reflection/get_type_methods", _ => GetMethods(typeof(Mission)));

            Get("/mission_reflection/execute/{id}/{method}", parameters => MissionReflectionExecute(parameters));
            Post("/mission_reflection/execute/{id}/{method}", parameters => MissionReflectionExecute(parameters));

            Get("/mission_reflection/get_status/{id}", parameters =>
            {
                try
                {
                    var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
                    if (mission == null)
                        return JsonConvert.SerializeObject(
                            new
                            {
                                Success = false,
                                Code = 500,
                                Data = "null",
                                Message = $"no mission of id {parameters.id}"
                            }, Formatting.Indented);

                    return JsonConvert.SerializeObject(
                        new { success = true, Code = 200, Data = mission.status, Message = "Success" },
                        Formatting.Indented);
                }
                catch (Exception ex)
                {
                    return JsonConvert.SerializeObject(
                        new { Success = false, Code = 500, Data = "null", result = ex.Message }, Formatting.Indented);
                }
            });

            Get("/mission_reflection/get_fields/{id}", parameters =>
            {
                try
                {
                    var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
                    if (mission == null)
                        return JsonConvert.SerializeObject(
                            new
                            {
                                Success = false,
                                Code = 500,
                                Data = "null",
                                Message = $"no mission of id {parameters.id}"
                            }, Formatting.Indented);

                    return JsonConvert.SerializeObject(
                        new
                        {
                            Success = true,
                            Code = 200,
                            Data = mission.fields.Select(x => { return new { Key = x.Key, Vaule = x.Value }; })
                                .ToList(),
                            Message = "Success"
                        },
                        Formatting.Indented);
                }
                catch (Exception ex)
                {
                    return JsonConvert.SerializeObject(
                        new { Success = false, Code = 500, Data = "null", result = ex.Message }, Formatting.Indented);
                }
            });

            Get("/mission_reflection/set_field/{id}/{field}/{value}", parameters =>
            {
                try
                {
                    var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
                    if (mission == null)
                        return JsonConvert.SerializeObject(
                            new { success = false, Data = "null", Message = $"no mission of id {parameters.id}" },
                            Formatting.Indented);

                    var fieldName = (string)parameters.field;
                    var fieldValue = (string)parameters.value;
                    mission.fields[fieldName] = fieldValue;

                    return JsonConvert.SerializeObject(
                        new { Success = true, Code = 200, Data = "null", Message = "Success" }, Formatting.Indented);
                }
                catch (Exception ex)
                {
                    return JsonConvert.SerializeObject(
                        new { Success = false, Code = 500, Data = "null", Message = ex.Message }, Formatting.Indented);
                }
            });

            Get("/mission_reflection/delete_field/{id}/{field}", parameters =>
            {
                try
                {
                    var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
                    if (mission == null)
                        return JsonConvert.SerializeObject(new
                        {
                            Success = false,
                            Code = 500,
                            Data = "null",
                            Message = $"no mission of id {parameters.id}"
                        }, Formatting.Indented);
                    var fieldName = (string)parameters.field;
                    if (!mission.fields.ContainsKey(fieldName))
                    {
                        return JsonConvert.SerializeObject(new
                        {
                            Success = false,
                            Code = 500,
                            Data = "null",
                            Message = $"mission not found field {parameters.field}"
                        }, Formatting.Indented);
                    }
                    mission.fields.Remove(fieldName);
                    return JsonConvert.SerializeObject(new
                    {
                        Success = true,
                        Code = 200,
                        Data = "null",
                        Message = "Success"
                    }, Formatting.Indented);
                }
                catch (Exception ex)
                {
                    return JsonConvert.SerializeObject(new
                    {
                        Success = false,
                        Code = 500,
                        Data = "null",
                        Message = ex.Message
                    }, Formatting.Indented);
                }
            });
            Get("/mission_reflection/get_mission/{id}", parameters =>
            {
                try
                {
                    var classMethodsDictionary = new Dictionary<string, List<MethodInfoDetails>>();
                    var mission = SimpleProject.proj.Missions.FirstOrDefault(m => m.id == (int)parameters.id);
                    if (mission == null)
                    {
                        return JsonConvert.SerializeObject(
                            new
                            {
                                Success = false,
                                Code = 500,
                                Data = "null",
                                Message = $"no mission of id {parameters.id}"
                            },
                            Formatting.Indented);
                    }

                    var method = mission.GetType()
                        .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                        .Where(m => m.GetCustomAttribute<MethodMember>() != null).Select(m =>
                        {
                            var attr = m.GetCustomAttribute<MethodMember>();
                            var param = m.GetParameters();
                            var ret = new MethodInfoDetails() { MethodName = m.Name };
                            var name = attr.Name;
                            if (name != null) ret.ButtonName = name;
                            var desc = attr.Description;
                            if (desc != null) ret.ButtonDescription = desc;
                            return ret;
                        }).ToList();
                    classMethodsDictionary[mission.name] = method;
                    return JsonConvert.SerializeObject(
                        new { Success = true, Code = 200, Data = classMethodsDictionary.Values.FirstOrDefault(), Message = "Success" });

                }
                catch (Exception e)
                {
                    return JsonConvert.SerializeObject(new
                    { Success = false, Code = 500, Data = "null", Message = e.Message });
                }
            });

            // 需讨论如何实现
            // Get["/save_parameters"] = _ => { };

            #region 创建任务[Fass发布任务]
            Post("/car/createTask", _ =>
            {
                Response response;
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var req = jReq.JsonTo<TaskRequest>();
                    switch (req.MissionType)
                    {
                        case "Transport":
                            CreateTransportTask:
                            (
                                responseResult.Success,
                                responseResult.Code,
                                responseResult.Message,
                                var _
                            ) = CreateTransportTask(req, true);
                            break;
                        default:
                            goto CreateTransportTask;
                    }
                    response = Response.AsText(
                        responseResult.ToJson(),
                        "application/json;charset=UTF-8"
                    );
                    return response;
                }
                catch (Exception ex)
                {
                    Diagnosis.Log(
                        $"起始站点匹配错误，请检查"
                            + ExceptionFormatter.FormatEx(ex)
                            + $"--time:{DateTime.Now.ToString()}",
                        "error",
                        true
                    );
                    responseResult.Success = false;
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = ex.Message;
                    response = Response.AsText(
                        responseResult.ToJson(),
                        "application/json;charset=UTF-8"
                    );
                    return response;
                }
            });
            #endregion

            #region 任务下发[Fass持续下发]
            Post("/car/carTask", _ =>
            {
                Response response;
                var responseResult = new BaseRespose<CarStateInfo>
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
                    string jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    TaskRequest req = jReq.JsonTo<TaskRequest>();
                    switch (req.MissionType)
                    {
                        case "Transport":
                            CheckTransportTask:
                            (
                                responseResult.Success,
                                responseResult.Code,
                                responseResult.Message,
                                responseResult.Data
                            ) = CreateTransportTask(req, false);
                            break;
                        default:
                            goto CheckTransportTask;
                    }
                    response = Response.AsText(
                        responseResult.ToJson(),
                        "application/json;charset=UTF-8"
                    );
                    //Diagnosis.Log(
                    //    $"carTask_Done:::consumeTime:{sw.ElapsedMilliseconds}",
                    //    "Interface",
                    //    true
                    //);
                    return response;
                }
                catch (Exception ex)
                {
                    Diagnosis.Log(
                        $"起始站点匹配错误，请检查"
                            + ExceptionFormatter.FormatEx(ex)
                            + $"--time:{DateTime.Now.ToString()}",
                        "error",
                        true
                    );
                    responseResult.Success = false;
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = ex.Message;
                    responseResult.Data = new CarStateInfo();
                    response = Response.AsText(
                        responseResult.ToJson(),
                        "application/json;charset=UTF-8"
                    );
                    return response;
                }
            });

            #endregion

            #region 状态查询
            Post("/car/carState", _ =>
            {
                Response response;
                try
                {
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
                    var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var req = jReq.JsonTo<GetCar>();
                    if (req.CarCode != "0")
                    {
                        var responseResult = new BaseRespose<CarStateInfo>
                        {
                            Success = true,
                            Code = (int)HttpStatusCode.OK,
                            Message = "success"
                        };
                        var singleCar = SimpleLib
                            .GetAllCars()
                            .OfType<Car>()
                            .FirstOrDefault(e =>
                                e.id.ToString() == req.CarCode && e.GetLastSite() != -1
                            );
                        if (singleCar != null)
                        {
                            responseResult.Data = GetCarStateInfo(req.CarCode);
                        }
                        else
                        {
                            responseResult.Success = false;
                            responseResult.Code = (int)HttpStatusCode.InternalServerError;
                            responseResult.Message = $"车辆carCode:{req.CarCode}不存在或未初始化";
                            responseResult.Data = new CarStateInfo();
                        }
                        response = Response.AsText(
                            responseResult.ToJson(),
                            "application/json;charset=UTF-8"
                        );
                        //Diagnosis.Log(
                        //    $"carState_Done:::consumeTime:{sw.ElapsedMilliseconds}",
                        //    "Interface",
                        //    true
                        //);
                        return response;
                    }
                    else
                    {
                        var responseResult = new BaseRespose<List<CarStateInfo>>
                        {
                            Success = true,
                            Code = (int)HttpStatusCode.OK,
                            Message = "success"
                        };
                        var carStateList = new List<CarStateInfo>();
                        var cars = SimpleLib.GetAllCars().OfType<Car>().ToList();
                        if (cars.Count > 0)
                        {
                            foreach (var car in cars)
                            {
                                var carStateInfo = GetCarStateInfo(car.name);
                                carStateList.Add(carStateInfo);
                            }
                            responseResult.Data = carStateList;
                        }
                        else
                        {
                            responseResult.Success = false;
                            responseResult.Code = (int)HttpStatusCode.InternalServerError;
                            responseResult.Message = "当前系统中无启用调度车辆";
                            responseResult.Data = carStateList;
                        }
                        response = Response.AsText(
                            responseResult.ToJson(),
                            "application/json;charset=UTF-8"
                        );
                        //Diagnosis.Log(
                        //    $"carState_Done:::consumeTime:{sw.ElapsedMilliseconds}",
                        //    "Interface",
                        //    true
                        //);
                        return response;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($@"agv/getCar => ex: {ex.Message}");
                    var responseResult = new BaseRespose<CarStateInfo>
                    {
                        Success = true,
                        Code = (int)HttpStatusCode.OK,
                        Message = "success"
                    };
                    responseResult.Success = false;
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = ex.Message;
                    responseResult.Data = new CarStateInfo();
                    response = Response.AsText(
                        responseResult.ToJson(),
                        "application/json;charset=UTF-8"
                    );
                    return response;
                }
            });
            #endregion

            #region 初始化小车
            Get("/car/reset/{cartId}", _ =>
            {
                var resp = new BaseRespose();
                try
                {
                    int cartId = _.cartId;
                    Car car = (Car)SimpleLib.GetCar(cartId);
                    //如果有任务不允许初始化
                    if (!car.tags.Contains("occupied"))
                    {
                        car.Reset();
                        car.tags.Add("idle", DateTime.Now.ToString());
                    }
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 现场维修
            Get("/car/repair/{cartId}", _ =>
            {
                var resp = new BaseRespose();
                try
                {
                    int cartId = _.cartId;
                    Car car = (Car)SimpleLib.GetCar(cartId);
                    car.Repair();
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 返厂维修
            Get("/car/blown/{cartId}", _ =>
            {
                var resp = new BaseRespose();
                try
                {
                    int cartId = _.cartId;
                    Car car = (Car)SimpleLib.GetCar(cartId);
                    var cdm = SimpleProject.proj.Missions.OfType<TransportMission>().First();
                    var deliver = cdm.GetDeliveries()
                        .Find(p => ((TransportDelivery)p).UsingCar.id == car.id);
                    if (deliver != null)
                    {
                        resp.Success = false;
                        resp.Code = 500;
                        resp.Message = "当前小车有任务需等任务结束后返厂";
                    }
                    else
                    {
                        car.AppendDebug("ui-blown");
                        Diagnosis.Post($"Car {car.name}({car.id}) blown");
                        car.NoSchedule();
                        car.siteID = -1;
                        car.tags.Clear();
                        car.status.usage.AddUsage(
                            "base",
                            new CarUsage.CarUsageInfo { scheduling = false, refreshing = false }
                        );
                        car.lstatus = "返厂检修";
                    }
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 站点启用
            Get("/site/enable/{siteId}", _ =>
            {
                var resp = new BaseRespose();
                try
                {
                    int siteId = _.siteId;
                    Site site = SimpleLib.GetSite(siteId);
                    if (site.tags.Contains("unavailable"))
                        site.tags.Remove("unavailable");
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 站点禁用
            Get("/site/disable/{siteId}", _ =>
            {
                var resp = new BaseRespose();
                try
                {
                    int siteId = _.siteId;
                    Site site = SimpleLib.GetSite(siteId);
                    if (!site.tags.Contains("unavailable"))
                        site.tags.Add("unavailable");
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 取消任务
            Post("/car/cancelTask", param =>
            {
                Response response;
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var req = jReq.JsonTo<TaskCancel>();
                    switch (req.MissionType)
                    {
                        case "Transport":
                            TransportCancel:
                            var cdm = SimpleProject
                                .proj.Missions.OfType<TransportMission>()
                                .First();
                            var deliver = cdm.GetDeliveries()
                                .Find(p => ((TransportDelivery)p).TaskId == req.TaskCode);
                            if (deliver != null)
                            {
                                deliver.Canceled = true;
                                if (!deliver.Cancel())
                                {
                                    responseResult.Success = false;
                                    responseResult.Code = 500;
                                    responseResult.Message = "任务取消失败";
                                    return responseResult;
                                }
                                else
                                {
                                    if (deliver.UsingCar != null)
                                    {
                                        var car = deliver.UsingCar;
                                        new Thread(() =>
                                        {
                                            try
                                            {
                                                car.AppendDebug("Clumsy Restarted");
                                                car.NoSchedule(true);
                                                car.siteID = -1;
                                                Commons.DeleteTag(car.tags, "occupied");
                                                if (car.address != null && car.address != "")
                                                {
                                                    SharedHttpClient.GetAsync(
                                                        $"http://{car.address}:8008/reset"
                                                    );
                                                }
                                                car.AppendDebug("restarting clumsy");
                                                //car.Get("reset");

                                                car.AppendDebug(
                                                    "wait for any pending task to flush."
                                                );

                                                car.status.programs.task.Wait();
                                                //car.Reset();
                                            }
                                            catch (Exception)
                                            {
                                                responseResult.Message = "重启C失败";
                                            }
                                        }).Start();
                                    }
                                }
                            }
                            else
                            {
                                responseResult.Success = false;
                                responseResult.Code = 500;
                                responseResult.Message = $"CDM中不存在任务id[{req.TaskCode}]";
                            }
                            break;
                        default:
                            goto TransportCancel;
                            break;
                    }
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (Exception e)
                {
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"任务取消失败！ ex:{e.Message}";
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
            });
            #endregion

            #region 获取Simple地图
            Get("/map/getMap", _ =>
            {
                var resp = new BaseRespose<Map>()
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };

                try
                {
                    resp.Data = Map.GetMap();
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 获取雷达地图

            Get("/map/getLidarMap", _ =>
            {
                var resp = new BaseRespose<LidarMap>()
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };

                try
                {
                    resp.Data = LidarMap.GetLidarMap().Result;
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });

            #endregion

            #region 获取所有小车信息
            Get("/car/getAllCars", _ =>
            {
                var resp = new BaseRespose<List<CarBaseInfo>>();
                try
                {
                    resp.Data = new List<CarBaseInfo>();
                    foreach (var car in SimpleLib.GetAllCars())
                    {
                        resp.Data.Add(CarBaseInfo.FromCar((Car)car));
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.StackTrace);
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 去某地
            Get("/car/goSite", param =>
            {
                var carCode = Request.Query["carCode"];
                var id = Request.Query["id"];
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    if (carCode != 0 && id != 0)
                    {
                        Car car = (Car)SimpleLib.GetCar(carCode);
                        Site site = SimpleLib.GetSite(id);
                        Commons.GoSite(car, site, 1);
                    }
                    var response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (Exception)
                {
                    return Response.AsText("调用小车去某地失败".ToJson(), "application/json");
                }
            });
            #endregion

            #region 获取任务列表
            Get("/task/getTask", _ =>
            {
                Response response;
                var resp = new BaseRespose<List<TaskRecord>>()
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };

                try
                {
                    var missions = SimpleProject
                        .proj.Missions.OfType<ChainedDeliveryMission>()
                        .ToList();
                    List<TaskRecord> deliveryList = new List<TaskRecord>();
                    if (missions.Count == 0)
                        return Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                    foreach (var cdm in missions)
                    {
                        var finishTaskList = cdm.GetDeliveries(true, true)
                            .Where(e => e.FinishTime > DateTime.Now.AddMinutes(-30))
                            .ToList(); //30min内已完成完成任务
                        var executingTaskList = cdm.GetDeliveries(); //未完成任务
                        foreach (var delivery in finishTaskList)
                        {
                            var temp = (TransportDelivery)delivery;
                            deliveryList.Add(
                                new TaskRecord
                                {
                                    TaskId = temp.TaskId,
                                    Name = $"{temp.Src} =>{temp.Dst}",
                                    CarId = temp.UsingCar.id.ToString(),
                                    CarName = temp.UsingCar.name,
                                    State = GetDeliveryStatus(temp),
                                    SrcSiteId = temp.Src.ToString(),
                                    DestSiteId = temp.Dst.ToString(),
                                    Priority = temp.Priority,
                                    StartTime = temp.StartTime,
                                    EndTime = temp.FinishTime,
                                    Created = temp.CreateTime
                                }
                            );
                        }

                        foreach (var delivery in executingTaskList)
                        {
                            var temp = (TransportDelivery)delivery;
                            deliveryList.Add(
                                new TaskRecord
                                {
                                    TaskId = temp.TaskId,
                                    Name = $"{temp.Src} =>{temp.Dst}",
                                    CarId = temp.UsingCar.id.ToString(),
                                    CarName = temp.UsingCar.name,
                                    State = GetDeliveryStatus(temp),
                                    SrcSiteId = temp.Src.ToString(),
                                    DestSiteId = temp.Dst.ToString(),
                                    Priority = temp.Priority,
                                    StartTime = temp.StartTime,
                                    EndTime = temp.FinishTime,
                                    Created = temp.CreateTime
                                }
                            );
                        }

                        resp.Data = deliveryList;
                    }
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 强制结束
            Get("/car/ForceStop/{cartId}", _ =>
            {
                #region
                /*   try
                   {
                       int cartId = _.cartId;
                       var car = (Car)SimpleLib.GetCar(cartId);

                       try
                       {
                           if (car == null)
                           {
                               resp.Success = false;
                               resp.Code = 500;
                               resp.Message = "小车在系统中没找到";
                           }
                           else
                           {
                               car.AppendDebug("ui-repair");
                               car.tags.Clear();
                               car.NoSchedule(makeUnavailable: false);
                               car.siteID = -1;
                               car.lstatus = "结束任务";
                               var cdm = SimpleProject
                                   .proj.Missions.OfType<TransportMission>()
                                   .First();
                               var deliver = cdm.GetDeliveries()
                                   .Find(p => ((TransportDelivery)p).usingCar.id == car.id);
                               if (deliver != null)
                               {
                                   deliver.canceled = true;
                                   if (!deliver.Cancel())
                                   {
                                       deliver.usingCar.UIIntercept();
                                       resp.Success = false;
                                       resp.Code = 500;
                                       resp.Message = "任务取消失败";
                                   }
                               }
                               new Thread(() =>
                               {
                                   try
                                   {
                                       //car.status.programs.task.Wait();
                                       HttpClient client = new HttpClient();
                                       client.GetAsync($"http://{car.address}:8008/reset");
                                   }
                                   catch
                                   {
                                       resp.Success = false;
                                       resp.Code = 500;
                                       resp.Message = "重启C失败";
                                   }
                               }).Start();

                               resp.Success = true;
                               resp.Code = 200;
                               resp.Message = "强制结束任务成功";
                           }
                       }
                       catch (Exception e)
                       {
                           resp.Success = false;
                           resp.Code = 500;
                           resp.Message = e.Message;
                       }
                   }
                   catch (Exception e)
                   {
                       resp.Success = false;
                       resp.Code = 500;
                       resp.Message = e.Message;
                   }*/
                #endregion
                var resp = new BaseRespose() { Message = "任务取消成功" };
                try
                {
                    int cartId = _.cartId;
                    var car = (Car)SimpleLib.GetCar(cartId);
                    car.NoSchedule(true);
                    car.siteID = -1;

                    Commons.ClearTags(car.tags);
                    car.tags.Clear();
                    var cdm = SimpleProject.proj.Missions.OfType<TransportMission>().First();
                    var deliver = cdm.GetDeliveries()
                        .Find(p => ((TransportDelivery)p).UsingCar.id == car.id);

                    int count = 0;

                    if (deliver != null)
                    {
                        deliver.Canceled = true;
                        if (!deliver.Cancel())
                        {
                            resp.Success = false;
                            resp.Code = 400;
                            resp.Message = "任务取消失败";
                            var res = Response.AsText(
                                resp.ToJson(),
                                "application/json;charset=UTF-8"
                            );
                            return res;
                        }
                    }

                    new Thread(() =>
                    {
                        try
                        {
                            SharedHttpClient.GetAsync($"http://{car.address}:8008/reset");
                            car.AppendDebug("restarting clumsy");
                            //car.Get("reset");

                            car.AppendDebug("wait for any pending task to flush.");

                            car.status.programs.task.Wait();
                            car.AppendDebug("Clumsy Restarted");
                            car.NoSchedule();
                            car.siteID = -1;
                            Commons.DeleteTag(car.tags, "occupied");
                            // car.Reset();
                        }
                        catch (Exception)
                        {
                            resp.Message = "重启C失败";
                        }
                    })
                    {
                        Name = $"ForceStop:{car.name}({car.id})"
                    }.Start();
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 重启电脑
            Get("/car/ReStart/{cartId}", _ =>
            {
                var resp = new BaseRespose();
                int cartId = _.cartId;
                var car = (Car)SimpleLib.GetCar(cartId);
                var task = Task.Run(() =>
                {
                    try
                    {
                        resp.Success = false;
                        resp.Code = 200;
                        resp.Message = "重启中";

                        // 创建一个Process对象
                        Process process = new Process();

                        // 设置启动信息
                        process.StartInfo.FileName = "shutdown";
                        process.StartInfo.Arguments = "/r /t 0"; // 重启电脑，立即执行
                        process.StartInfo.CreateNoWindow = true; // 不显示窗口
                        process.StartInfo.UseShellExecute = false; // 不使用操作系统外壳程序启动进程

                        // 启动进程
                        process.Start();
                    }
                    catch (Exception e)
                    {
                        resp.Success = false;
                        resp.Code = 400;
                        resp.Message = e.Message;
                    }
                });
                task.Wait();
                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 停接任务
            Get("/car/stopReceiveTask/{cartId}", _ =>
            {
                var resp = new BaseRespose();
                int cartId = _.cartId;
                try
                {
                    var car = (Car)SimpleLib.GetCar(cartId);
                    if (car != null)
                    {
                        if (!car.fields.ContainsKey("StopAccept"))
                        {
                            Commons.AddOrUpdateCarField(car, "StopAccept", "1");
                        }
                        else
                        {
                            Commons.DeleteCarField(car, "StopAccept");
                        }
                    }
                    else
                    {
                        resp.Success = false;
                        resp.Code = 500;
                        resp.Message = "找不到对应小车";
                    }
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }

                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 获取小车信息
            Get("/car/carInfo/{cartId}", _ =>
            {
                var resp = new BaseRespose<CarInfo>();
                int cartId = _.cartId;
                try
                {
                    var car = (Car)SimpleLib.GetCar(cartId);
                    if (car != null)
                    {
                        resp.Data = new CarInfo()
                        {
                            Name = car.name,
                            Address = car.address,
                            Speed = car.status.enums.TryGetValue(
                                "ActualLeftWheelVelocity",
                                out var statusEnum
                            )
                                ? statusEnum
                                : car.speed.ToString(),
                            Voltage = car.status.enums.TryGetValue("soc", out var soc)
                                ? float.Parse(soc)
                                : -1,
                            Code = car.id.ToString(),
                            siteId = car.GetLastSite()
                        };
                    }
                }
                catch (Exception e)
                {
                    resp.Success = false;
                    resp.Code = 500;
                    resp.Message = e.Message;
                }

                var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
                return response;
            });
            #endregion

            #region 去待命点
            Get("/car/goToStandby", param =>
            {
                var CarCode = Request.Query["carCode"];
                //var id = Request.Query["id"];
                Response response;
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var car = (Car)SimpleLib.GetCar(CarCode);
                    if (car != null)
                    {
                        var carGroup = car.fields.TryGetValue("group", out var value)
                            ? value
                            : "all";
                        var targetPlan = Commons.GetNearestPlan(
                            (Car)car,
                            site =>
                                site.fields.ContainsKey("standby")
                                && carGroup.Equals(
                                    site.fields.TryGetValue("group", out var value) ? value : "all"
                                )
                                && site.fields["standby"] == "true"
                        );
                        if (targetPlan != null)
                        {
                            Commons.GoSite(car, targetPlan.Destination, 1);
                        }
                    }
                    else
                    {
                        responseResult.Success = false;
                        responseResult.Code = 500;
                        responseResult.Message = "没有找到任务小车";
                    }
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (Exception)
                {
                    return Response.AsText("调用小车去待命点失败".ToJson(), "application/json");
                }
            });
            #endregion

            #region 去充电点
            Get("/car/goToCharge", param =>
            {
                var CarCode = Request.Query["carCode"];
                //var id = Request.Query["id"];
                Response response;
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var car = (Car)SimpleLib.GetCar(CarCode);
                    if (car != null)
                    {
                        /*     var carGroup = car.fields.TryGetValue("group", out var value) ? value : "all";
                             var targetPlan = Commons.GetNearestPlan((Car)car, site =>
                                 site.fields.ContainsKey("charge")
                                 && site.fields["charge"] == "true" && carGroup.Equals(site.fields.TryGetValue("group", out var value) ? value : "all")
                             );
                             if (targetPlan != null)
                             {
                                 Diagnosis.Post($"小车路径规划成功目标充电位{targetPlan.Destination}", "去充电",true);
                                 Commons.GoSite(car, targetPlan.Destination, 1);
                             }
                             else
                             {

                                 Diagnosis.Post("小车路径规划失败", "去充电", true);

                             }*/

                        Commons.AddOrUpdateTag(car.tags, "shouldCharge", "true");
                    }
                    else
                    {
                        responseResult.Success = false;
                        responseResult.Code = 500;
                        responseResult.Message = "没有找到任务小车";
                    }
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (Exception)
                {
                    return Response.AsText("调用小车去充电电点失败".ToJson(), "application/json");
                }
            });
            #endregion

            #region 暂停恢复
            Get("/car/startOrPause", param =>
            {
                var carCode = Request.Query["CarCode"];
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };

                try
                {
                    if (carCode == 0)
                    {
                        responseResult.Success = false;
                        responseResult.Code = (int)HttpStatusCode.BadRequest;
                        responseResult.Message = "没有找到任务小车";
                        return Response.AsJson(responseResult);
                    }

                    ClumsyCar car = SimpleLib.GetCar(carCode) as ClumsyCar;
                    if (car == null)
                    {
                        responseResult.Success = false;
                        responseResult.Code = (int)HttpStatusCode.NotFound;
                        responseResult.Message = "未找到对应的小车";
                        return Response.AsJson(responseResult);
                    }

                    string releaseStatus = Commons.GetCarStatus(car, "ISRelease");

                    try
                    {
                        ToggleCarReleaseStatus(car, releaseStatus);
                    }
                    catch (Exception ex)
                    {
                        responseResult.Success = false;
                        responseResult.Code = (int)HttpStatusCode.InternalServerError;
                        responseResult.Message = $"暂停恢复失败 => ex:{ExceptionFormatter.FormatEx(ex)}";
                        Diagnosis.Log($"暂停恢复失败 => ex:{ExceptionFormatter.FormatEx(ex)}");
                    }

                    return Response.AsJson(responseResult);
                }
                catch (Exception ex)
                {
                    responseResult.Success = false;
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"暂停恢复失败 => ex:{ExceptionFormatter.FormatEx(ex)}";
                    return Response.AsJson(responseResult);
                }
            });
            #endregion

            #region 暂停任务/恢复任务
            Post("/car/stopOrPauseTask", param =>
            {
                Response response;
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var result = jReq.JsonTo<TaskCancel>();
                    var taskCode = result.TaskCode;
                    var cdms = SimpleProject
                        .proj.Missions.OfType<ChainedDeliveryMission>()
                        .ToList();

                    if (cdms.Count == 0)
                    {
                        responseResult.Success = false;
                        responseResult.Code = 500;
                        responseResult.Message = "未找到CDM进程";
                        return Response.AsText(responseResult.ToJson(), "application/json");
                    }

                    Delivery deliver = null;
                    foreach (var cdm in cdms)
                    {
                        deliver = cdm.GetDeliveries(includeAborted: true)
                            .FirstOrDefault(p => p.TaskId == taskCode);
                        if (deliver != null)
                            break;
                    }

                    if (deliver == null)
                    {
                        responseResult.Success = false;
                        responseResult.Code = 500;
                        responseResult.Message = $"CDM中不存在任务id[{taskCode}]";
                        return Response.AsText(responseResult.ToJson(), "application/json");
                    }

                    deliver.Terminated = result.TaskStatus == "1";
                    var status = 0;

                    if (deliver.UsingCar != null)
                    {
                        status = (deliver.OnTerminated?.Invoke(deliver, result.TaskStatus)).Result;
                    }

                    if (status != 1)
                    {
                        responseResult.Success = false;
                        responseResult.Code = 500;
                        responseResult.Message = deliver.Terminated ? "暂停任务停止小车失败" : "恢复任务失败";
                    }

                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (JsonSerializationException jsonEx)
                {
                    responseResult.Code = (int)HttpStatusCode.BadRequest;
                    responseResult.Message = $"JSON解析失败！ ex:{jsonEx.Message}";
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (Exception e)
                {
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"任务取消失败！ ex:{e.Message}";
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
            });

            #endregion

            #region 设置充电参数
            Post("/car/setChargingSettings", param =>
            {
                Response response;
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var chargingSetting = jReq.JsonTo<ChargingSetting>();

                    // 这里可以根据 ChargingSetting 的属性进行具体的业务逻辑处理
                    // 例如：
                    if (chargingSetting.CarMinBattery < 0 || chargingSetting.CarMaxBattery > 100)
                    {
                        responseResult.Success = false;
                        responseResult.Code = 400;
                        responseResult.Message = "充电电量范围不合法";
                    }
                    else
                    {
                        // 假设我们有一个方法来应用这些充电设置
                        ApplyChargingSettings(chargingSetting);
                    }

                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (Exception e)
                {
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"设置充电参数失败！ ex:{e.Message}";
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
            });

            #endregion
            #region 设置包络参数
            Post("/car/setEnvelopeSetting", param =>
            {
                Response response;
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var envelopeSetting = jreq.JsonTo<EnvelopeSetting>();
                    // 读取本地 JSON 文件
                    var simpleFilePath =
                        $"{System.AppDomain.CurrentDomain.BaseDirectory}/simple.json";
                    var simpleJson = File.ReadAllText(simpleFilePath);
                    var simpleConfig = simpleJson.JsonTo<SimpleConfig>();
                    var jsonFilePath = "";
                    if (simpleConfig != null && simpleConfig.Autoload != null)
                    {
                        jsonFilePath =
                            $"{System.AppDomain.CurrentDomain.BaseDirectory}/{simpleConfig.Autoload}";
                    }
                    else
                    {
                        responseResult.Code = (int)HttpStatusCode.BadRequest;
                        responseResult.Message = "修改文件路径不对";
                        response = Response.AsText(responseResult.ToJson(), "application/json");
                        return response;
                    }
                    //var jsonFilePath = $"{System.AppDomain.CurrentDomain.BaseDirectory}/0123.json";
                    var jsonData = File.ReadAllText(jsonFilePath);
                    var jsonObject = JObject.Parse(jsonData);

                    // 更新或添加属性
                    // 获取或创建 "conf" 节点
                    var confNode = jsonObject["conf"];
                    if (confNode == null || confNode.Type != JTokenType.Object)
                    {
                        confNode = new JObject();
                        jsonObject["conf"] = confNode;
                    }

                    // 更新 JSON 数据
                    confNode[envelopeSetting.Name] = envelopeSetting.Value;
                    ;

                    // 将修改后的数据写回 JSON 文件
                    File.WriteAllText(jsonFilePath, jsonObject.ToString());

                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (Exception e)
                {
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"设置包络参数失败！ ex:{e.Message}";
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
            });
            #endregion

            #region 设置交管参数
            Post("/car/setTrafficControlSetting", param =>
            {
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var trafficControlSetting = jreq.JsonTo<TrafficControlSetting>();
                    // 读取本地 JSON 文件
                    var simpleFilePath =
                        $"{System.AppDomain.CurrentDomain.BaseDirectory}/simple.json";
                    var simpleJson = File.ReadAllText(simpleFilePath);
                    var simpleConfig = simpleJson.JsonTo<SimpleConfig>();
                    var jsonFilePath = "";
                    if (simpleConfig != null && simpleConfig.Autoload != null)
                    {
                        jsonFilePath =
                            $"{System.AppDomain.CurrentDomain.BaseDirectory}/{simpleConfig.Autoload}";
                    }
                    else
                    {
                        responseResult.Code = (int)HttpStatusCode.BadRequest;
                        responseResult.Message = "修改文件路径不对";
                    }
                    // 读取本地 JSON 文件路径
                    // jsonFilePath = $"{System.AppDomain.CurrentDomain.BaseDirectory}/0123.json";
                    if (!File.Exists(jsonFilePath))
                    {
                        throw new FileNotFoundException(
                            $"JSON file not found at path: {jsonFilePath}"
                        );
                    }

                    // 读取并解析 JSON 文件
                    var jsonData = File.ReadAllText(jsonFilePath);
                    var jsonObject = JObject.Parse(jsonData);

                    // 获取或创建 "conf" 节点
                    var confNode = jsonObject["conf"];
                    if (confNode == null || confNode.Type != JTokenType.Object)
                    {
                        confNode = new JObject();
                        jsonObject["conf"] = confNode;
                    }

                    // 更新 JSON 数据
                    confNode[trafficControlSetting.Name] = trafficControlSetting.Value;

                    // 将修改后的数据写回 JSON 文件
                    File.WriteAllText(jsonFilePath, jsonObject.ToString());

                    return Response.AsJson(responseResult);
                }
                catch (JsonSerializationException jsonEx)
                {
                    responseResult.Code = (int)HttpStatusCode.BadRequest;
                    responseResult.Message = $"JSON解析失败！ ex:{jsonEx.Message}";
                }
                catch (Exception e)
                {
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"设置交管控制参数失败！ ex:{e.Message}";
                }

                return Response.AsJson(responseResult);
            });
            #endregion

            #region 删除配置参数
            Post("/car/delControlSetting", param =>
            {
                Response response;
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var keysToRemove = jreq.JsonTo<List<string>>();
                    // 读取本地 JSON 文件
                    var simpleFilePath =
                        $"{System.AppDomain.CurrentDomain.BaseDirectory}/simple.json";
                    var simpleJson = File.ReadAllText(simpleFilePath);
                    var simpleConfig = simpleJson.JsonTo<SimpleConfig>();
                    var jsonFilePath = "";
                    if (simpleConfig != null && simpleConfig.Autoload != null)
                    {
                        jsonFilePath =
                            $"{System.AppDomain.CurrentDomain.BaseDirectory}/{simpleConfig.Autoload}";
                    }
                    else
                    {
                        responseResult.Code = (int)HttpStatusCode.BadRequest;
                        responseResult.Message = "修改文件路径不对";
                    }

                    if (!File.Exists(jsonFilePath))
                    {
                        throw new FileNotFoundException(
                            $"JSON file not found at path: {jsonFilePath}"
                        );
                    }
                    var jsonData = File.ReadAllText(jsonFilePath);
                    var jsonObject = JObject.Parse(jsonData);
                    var confNode = jsonObject["conf"] as JObject;

                    if (confNode == null)
                    {
                        confNode = new JObject();
                        jsonObject["conf"] = confNode;
                    }
                    if (confNode != null)
                    {
                        foreach (var key in keysToRemove)
                        {
                            if (confNode.ContainsKey(key))
                            {
                                confNode.Remove(key);
                            }
                        }

                        // 将修改后的数据写回 JSON 文件
                        File.WriteAllText(jsonFilePath, jsonObject.ToString());
                    }

                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (JsonSerializationException jsonEx)
                {
                    responseResult.Code = (int)HttpStatusCode.BadRequest;
                    responseResult.Message = $"JSON解析失败！ ex:{jsonEx.Message}";
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (FileNotFoundException fnfEx)
                {
                    responseResult.Code = (int)HttpStatusCode.NotFound;
                    responseResult.Message = $"文件未找到！ ex:{fnfEx.Message}";
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
                catch (Exception e)
                {
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"设置控制参数失败！ ex:{e.Message}";
                    response = Response.AsText(responseResult.ToJson(), "application/json");
                    return response;
                }
            });
            #endregion

            #region 删除路径规划参数设置
            Post("/car/delPlanRulesControlSetting", param =>
            {
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var planRulesSettings = jreq.JsonTo<List<PlanRulesSetting>>();
                    if (planRulesSettings.Count() < 0)
                    {
                        responseResult.Code = (int)HttpStatusCode.BadRequest;
                        responseResult.Message = "没有需要删除的路径参数";
                        return Response.AsJson(responseResult);
                    }
                    foreach (var planRules in planRulesSettings)
                    {
                        //根据参数，站点ID 找到该站点，如果站点有这个字段则删除，没有不用管
                        Site site = SimpleLib.GetSite(int.Parse(planRules.NodeId));
                        if (site == null)
                        {
                            responseResult.Code = (int)HttpStatusCode.BadRequest;
                            responseResult.Message = "需要修改属性的站点不存在";
                            return Response.AsJson(responseResult);
                        }
                        if (site.fields.TryGetValue(planRules.Name, out var value))
                        {
                            site.fields.Remove(planRules.Name);
                        }
                    }

                    return Response.AsJson(responseResult);
                }
                catch (JsonSerializationException jsonEx)
                {
                    responseResult.Code = (int)HttpStatusCode.BadRequest;
                    responseResult.Message = $"JSON解析失败！ ex:{jsonEx.Message}";
                }
                catch (Exception e)
                {
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"删除路径规划参数失败！ ex:{e.Message}";
                }

                return Response.AsJson(responseResult);
            });
            #endregion

            #region 设置路径规划参数
            Post("/car/setPlanRulesControlSetting", param =>
            {
                var responseResult = new BaseRespose
                {
                    Success = true,
                    Code = (int)HttpStatusCode.OK,
                    Message = "success"
                };
                try
                {
                    var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    var planRulesSetting = jreq.JsonTo<PlanRulesSetting>();
                    if (planRulesSetting == null)
                    {
                        responseResult.Code = (int)HttpStatusCode.BadRequest;
                        responseResult.Message = "需要修改属性的站点不存在";
                        return Response.AsJson(responseResult);
                    }
                    Site site = SimpleLib.GetSite(int.Parse(planRulesSetting.NodeId));
                    if (site == null)
                    {
                        responseResult.Code = (int)HttpStatusCode.BadRequest;
                        responseResult.Message = "需要修改属性的站点不存在";
                        return Response.AsJson(responseResult);
                    }
                    //判断站点属性是否存在，存在则修改，不存在则添加
                    if (site.fields.TryGetValue(planRulesSetting.Name, out var value))
                    {
                        site.fields[planRulesSetting.Name] = planRulesSetting.Value;
                    }
                    else
                    {
                        site.fields.Add(planRulesSetting.Name, planRulesSetting.Value);
                    }
                    return Response.AsJson(responseResult);
                }
                catch (JsonSerializationException jsonEx)
                {
                    responseResult.Code = (int)HttpStatusCode.BadRequest;
                    responseResult.Message = $"JSON解析失败！ ex:{jsonEx.Message}";
                }
                catch (Exception e)
                {
                    responseResult.Code = (int)HttpStatusCode.InternalServerError;
                    responseResult.Message = $"设置路径规划参数失败！ ex:{e.Message}";
                }

                return Response.AsJson(responseResult);
            });
            #endregion

            Get("/api/QrMap", _ =>
            {
                return QrMapJson;
            });

            Post("/api/CreateSite", o =>
            {
                try
                {
                    string jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
                    QrSite site = JsonConvert.DeserializeObject<QrSite>(jreq);
                    var newSite = new UISite() { x = site.X, y = site.Y };
                    Console.WriteLine($"x:{site.X},y:{site.Y}");
                    var d = SimpleLib
                        .GetAllSites()
                        .Select(p => LessMath.dist(site.X, site.Y, p.x, p.y));
                    if (d.Any() && d.Min() < 3)
                    {
                        Console.WriteLine($"重复设置站点？");
                        return JsonConvert.SerializeObject(
                            new { data = new { success = false, message = "设置站点失败,重复设置站点？" } }
                        );
                    }

                    SimpleLib.SetSite(newSite);
                    var ss = SimpleLib
                        .GetAllSites()
                        .OrderBy(p => LessMath.dist(site.X, site.Y, p.x, p.y))
                        .First();
                    ss.fields["th"] = (site.Th).ToString();
                    ss.fields["tag"] = (site.Tag).ToString();
                    return JsonConvert.SerializeObject(
                        new { data = new { success = true, message = "设置站点成功" } }
                    );
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    return JsonConvert.SerializeObject(
                        new { data = new { success = false, message = "设置站点失败" + e } }
                    );
                }
            });

            #region OTA获取车辆列表
            Get("/api/agv/list", _ =>
            {
                List<Object> cars = new List<Object>();
                foreach (var car in SimpleLib.GetAllCars().OfType<Car>())
                {
                    var station = SimpleLib
                        .GetAllSites()
                        .ToList()
                        .FirstOrDefault(site =>
                            site.id == car.status.holdingLocks.FirstOrDefault()
                            && site.name.Contains("TaskStation")
                        );
                    var statusV = car.status.enums.ContainsKey("actualV")
                        ? float.Parse(car.status.enums["actualV"])
                        : 0;
                    car.status.enums.TryGetValue("electricCurrent", out var electricCurrent);
                    var agv_status = "";
                    if (statusV == 0)
                    {
                        agv_status = "停止";
                    }
                    else if (statusV > 0)
                    {
                        agv_status = "运行中";
                    }
                    if (
                        statusV == 0
                        && electricCurrent != null
                        && electricCurrent != ""
                        && float.Parse(electricCurrent) * 0.01f > 0
                    )
                    {
                        agv_status = "充电中";
                    }

                    cars.Add(
                        new
                        {
                            agv_id = car.id,
                            agv_name = car.name,
                            agv_ip = car.address,
                            //agv_status = car.tags["carStatu"],
                            //agv_status = car.tags.Contains("carStatu") ? car.tags["carStatu"] : "OFFLINE",
                            energy = car.status.enums.ContainsKey("soc")
                                ? float.Parse(car.status.enums["soc"])
                                : -1,
                            /*   x = tPos.Item1,
                               y = tPos.Item2,
                               th = tPos.Item3,*/
                            x = car.x,
                            y = car.y,
                            th = car.th,
                            speed = Commons.CarValue(car, "sendSpeed"),
                            fault = car.status.enums.ContainsKey("mAlarm")
                                ? car.status.enums["mAlarm"]
                                : "正常",
                            siteId = car.GetLastSite(),
                            // materialinfo =new string[3] { "materialinfo1", "materialinfo2", "materialinfo3" }
                            stationInfo = station != null
                                ? new { stationID = station.id, staionName = station.name }
                                : null,

                            agv_status = agv_status
                        }
                    );
                }
                return JsonConvert.SerializeObject(
                    new
                    {
                        code = 200,
                        message = "ok",
                        data = cars
                    }
                );
            });
            #endregion

            #region 第三方交管
            Post("api/agv/traffic", _ =>
            {
                try
                {
                    string jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();

                    var Traffic = JsonConvert.DeserializeObject<TrafficRequestModel>(jreq);

                    var Area = TrafficInterlockMission.TrafficAreaList.Find(t => t.AreaName == Traffic.AreaName);

                    if (Traffic != null && Area != null)
                    {
                        if (Traffic.IsOccupy && !Area.IsOccupy)
                        {
                            lock (TrafficInterlockMission.TrafficAreaList)
                            {
                                Area.IsOccupy = true; Area.ControllerName = Traffic.ControllerName;
                            }

                            return JsonConvert.SerializeObject(new { data = new { success = true, message = "申请管制区成功" } });


                        }
                        else if (!Traffic.IsOccupy && Area.ControllerName == Traffic.ControllerName)
                        {
                            lock (TrafficInterlockMission.TrafficAreaList)
                            {
                                Area.IsOccupy = false; Area.ControllerName = string.Empty;
                            }

                            return JsonConvert.SerializeObject(new { data = new { success = true, message = "释放管制区成功" } });

                        }
                    }

                    return JsonConvert.SerializeObject(new { data = new { success = false, message = "失败" } });
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);

                    return JsonConvert.SerializeObject(new { data = new { success = false, message = "设置交管失败" + e } });
                }
            });
            #endregion
        }

        private void ToggleCarReleaseStatus(ClumsyCar car, string currentStatus)
        {
            int targetStatus = (currentStatus == "1") ? 0 : 1;
            string command = $"pilot.ISRelease={targetStatus};";

            while (Commons.GetCarStatus(car, "ISRelease") == currentStatus)
            {
                car.ImmediateCommand(command);
                Thread.Sleep(100);
            }
        }

        private void ApplyChargingSettings(ChargingSetting settings)
        {
            Console.WriteLine("开始处理充电配置参数的逻辑");
            // 这里是应用充电设置的具体逻辑
            // 例如，更新设备的充电参数等
            var chargeMission = SimpleProject
                .proj.Missions.OfType<AbstractChargeLogiceMission>()
                .FirstOrDefault();
            if (chargeMission == null)
                return;
            Commons.AddOrUpdateMissionField(
                chargeMission,
                "mustChargeSoc",
                settings.CarMinBattery.ToString()
            );
            Commons.AddOrUpdateMissionField(
                chargeMission,
                "fullChargeSoc",
                settings.CarMaxBattery.ToString()
            );
            Commons.AddOrUpdateMissionField(
                chargeMission,
                "taskAvailableSoc",
                settings.TaskAvailableBattery.ToString()
            );
            Commons.AddOrUpdateMissionField(
                chargeMission,
                "mustChargeSeconds",
                settings.CarIdleSecond.ToString()
            );
            Commons.AddOrUpdateMissionField(
                chargeMission,
                "idleChargeSoc",
                settings.CarIdleChargeBattery.ToString()
            );
        }

        private (bool, int, string, CarStateInfo) CreateTransportTask(
            TaskRequest req,
            bool isCreate
        )
        {
            var transportMission = SimpleProject.proj.Missions.OfType<TransportMission>().First();
            //校验任务重复
            if (
                transportMission
                    .GetDeliveries(true)
                    .FindAll(p => ((TransportDelivery)p).TaskId == req.TaskCode)
                    .Count > 0
            )
            {
                return (
                    false,
                    (int)HttpStatusCode.InternalServerError,
                    $"taskCode:{req.TaskCode}已经存在",
                    GetCarStateInfo(req.CarCode)
                );
            }
            //判定指定车辆是否存在
            Car car = null;
            if (!string.IsNullOrWhiteSpace(req.CarCode))
            {
                car = SimpleLib
                    .GetAllCars()
                    .OfType<Car>()
                    .FirstOrDefault(e => e.id.ToString() == req.CarCode);
                if (car == null || car.status.holdingLocks.FirstOrDefault() == -1)
                {
                    return (
                        false,
                        (int)HttpStatusCode.InternalServerError,
                        $"传入车辆code{req.CarCode}不存在或没有初始化",
                        new CarStateInfo()
                    );
                }
            }
            //判断node的个数
            switch (req.Nodes.Count)
            {
                case 2:
                    Diagnosis.Log(
                        $"receiveTask:[TaskId ={req.TaskCode},carId = {req.CarCode},src = {req.Nodes[0].Code},dst = {req.Nodes[1].Code}",
                        "task",
                        true
                    );
                    break;
                case 1:
                    if (car == null)
                        return (
                            false,
                            (int)HttpStatusCode.InternalServerError,
                            $"创建单点任务时，未指定车辆",
                            new CarStateInfo()
                        );
                    Diagnosis.Log(
                        $"receiveTask:[TaskId ={req.TaskCode},carId = {req.CarCode},dst = {req.Nodes[0].Code}",
                        "task",
                        true
                    );
                    break;
                default:
                    return (
                        false,
                        (int)HttpStatusCode.InternalServerError,
                        $"创建任务时，传入站点个数不对",
                        new CarStateInfo()
                    );
            }

            //站点存在判断,默认都是双点任务
            var siteCodes = req.Nodes.Select(e => e.Code).ToArray();
            if (!Commons.IsSceneSiteByCode(siteCodes))
            {
                return (
                    false,
                    (int)HttpStatusCode.InternalServerError,
                    $"不存在设定站点 => taskCode:{req.TaskCode}",
                    new CarStateInfo()
                );
            }

            var src =
                req.Nodes.Count == 2
                    ? SimpleLib.GetSite(req.Nodes[0].Code)
                    : SimpleLib.GetSite(car.status.holdingLocks.First()); //如果是单点任务，默认当前未知为起点
            var dst =
                req.Nodes.Count == 2
                    ? SimpleLib.GetSite(req.Nodes[1].Code)
                    : SimpleLib.GetSite(req.Nodes[0].Code);

            var d = new TransportDelivery
            {
                Src = src.id,
                Dst = dst.id,
                CarType = req.CarType,
                TaskId = req.TaskCode,
                TaskType = req.TaskType,
                Material = req.Material,
                Priority = req.priority,
                MaterialLength = req.ContainerSize != null ? (float)req.ContainerSize.Length : -1,
                MaterialWidth = req.ContainerSize != null ? (float)req.ContainerSize.Width : -1,
            };
            if (car != null)
            {
                d.UsingCar = car;
            }

            d.FetchPlanInfo["MaterialLength"] = d.MaterialLength + "";
            d.FetchPlanInfo["MaterialWidth"] = d.MaterialWidth + "";
            if (d.Src == d.Dst)
            {
                d.FetchPlanInfo["action"] = "/";
                d.PutPlanInfo["action"] = "/";
            }
            // 初始化回调配置，确保任务在各阶段触发统一回调
            d.ReportOnStarted = true;
            d.ReportOnFetched = true;
            d.ReportOnPut = true;
            d.ReportOnFinished = true;
            d.ReportOnFailed = true;
            d.ReportOnTerminated = true;

            // 根据 ReportOn* 写入 key 列表
            if (d.ReportOnStarted)
                d.OnStartCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnStarted);
            if (d.ReportOnFetched)
                d.DoneFetchCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnFetched);
            if (d.ReportOnPut)
                d.DonePutCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnPut);
            if (d.ReportOnFinished)
                d.DoneMissionCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnFinished);
            if (d.ReportOnFailed)
                d.FailedCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnFailed);
            if (d.ReportOnTerminated)
                d.OnTerminatedCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnTerminated);

            // 统一通过 Attacher 挂载回调，便于持久化与恢复
            DeliveryCallbackAttacher.AttachAll(d);

            transportMission.Enqueue(d);
            Diagnosis.Log($"Add task =>{d.ToJson()}，req:{req.ToJson()}");
            return (true, (int)HttpStatusCode.OK, "success", GetCarStateInfo(req.CarCode));
        }

        private class GetCar
        {
            public string CarCode;
        }

        public CarStateInfo GetCarStateInfo(string carCode)
        {
            try
            {
                var transportMission = SimpleProject
                    .proj.Missions.OfType<TransportMission>()
                    .FirstOrDefault();
                if (string.IsNullOrEmpty(carCode))
                    return new CarStateInfo();

                var singleCar = SimpleLib
                    .GetAllCars()
                    .OfType<Car>()
                    .FirstOrDefault(e => e.id.ToString() == carCode && e.GetLastSite() != -1);
                if (singleCar == null)
                    return new CarStateInfo();

                var runningTask = (TransportDelivery)
                    transportMission
                        .GetDeliveries()
                        .FindAll(p =>
                            (
                                p.GetStatus() == DeliveryStatus.Fetching
                                || p.GetStatus() == DeliveryStatus.Putting
                            )
                            && p.UsingCar.id == singleCar.id
                        )
                        .FirstOrDefault(); //获取当前车辆正在运行的任务
                var finishedTask = (TransportDelivery)
                    transportMission
                        .GetDeliveries(true)
                        .FindAll(p =>
                            p.GetStatus() == DeliveryStatus.Finished
                            && p.UsingCar.id == singleCar.id
                        )
                        .OrderByDescending(e => e.FinishTime)
                        .FirstOrDefault(); //获取最近完成的任务
                var waitingTask = (TransportDelivery)
                    transportMission
                        .GetDeliveries()
                        .FindAll(p =>
                            p.GetStatus() == DeliveryStatus.Waiting
                            && p.UsingCar != null
                            && p.UsingCar.id == singleCar.id
                        )
                        .OrderBy(e => e.CreateTime)
                        .FirstOrDefault();
                var taskList = new List<TaskInfo>();
                var actions = new List<TaskAction>();
                //string carState = SwitchCarState(singleCar);
                var isOnline = false;
                string carState = SwitchCarState(singleCar, ref isOnline);
                //var resNodes = new List<ResponseNode>();
                if (finishedTask != null)
                {
                    taskList.Add(
                        new TaskInfo()
                        {
                            Code = finishedTask.TaskId,
                            State = "Completed",
                            Nodes = new List<ResponseNode>()
                            {
                                new()
                                {
                                    //Code = Commons.GetSiteCodeById(finishedTask.src)
                                    Code = finishedTask.Src.ToString()
                                },
                                new()
                                {
                                    //Code = Commons.GetSiteCodeById(finishedTask.dst)
                                    Code = finishedTask.Dst.ToString()
                                }
                            }
                        }
                    );
                }

                if (runningTask != null)
                {
                    taskList.Add(
                        new TaskInfo()
                        {
                            Code = runningTask.TaskId,
                            State = "Running",
                            Nodes = new List<ResponseNode>()
                            {
                                new()
                                {
                                    //Code = Commons.GetSiteCodeById(runningTask.src)
                                    Code = runningTask.Src.ToString()
                                },
                                new()
                                {
                                    //Code = Commons.GetSiteCodeById(runningTask.dst)
                                    Code = runningTask.Dst.ToString()
                                }
                            }
                        }
                    );
                }

                if (waitingTask != null)
                {
                    taskList.Add(
                        new TaskInfo()
                        {
                            Code = waitingTask.TaskId,
                            State = "Distributed",
                            Nodes = new List<ResponseNode>()
                            {
                                new()
                                {
                                    //Code = Commons.GetSiteCodeById(waittingTask.src)
                                    Code = waitingTask.Src.ToString()
                                },
                                new()
                                {
                                    //Code = Commons.GetSiteCodeById(waittingTask.dst)
                                    Code = waitingTask.Dst.ToString()
                                }
                            }
                        }
                    );
                }

                var carId = singleCar.id;
                var alarmsList = new List<CarAlarm>();
                if (
                    singleCar.status.enums.ContainsKey("AlarmInfo")
                    && !string.IsNullOrWhiteSpace(singleCar.status.enums["AlarmInfo"])
                )
                {
                    string alarmMessage = singleCar.status.enums["AlarmInfo"].TrimEnd(',');
                    string[] alarms = alarmMessage.Split(',');
                    foreach (string alarm in alarms)
                    {
                        string[] info = alarm.Split('.');
                        if (info.Length == 2)
                        {
                            alarmsList.Add(new CarAlarm() { Code = info[0], Name = info[1] });
                        }
                    }
                }

                var currentSite = SimpleLib.GetSite(singleCar.status.holdingLocks.FirstOrDefault());
                // HashSet<Tuple<int, int>> blockedBy = singleCar.status.blockedBy;
                var blockedBy = singleCar.status.blockedBy.ToHashSet();
                List<BlockedByItem> blockedByItems = new List<BlockedByItem>();
                //var BlockedBy = string.Empty;
                for (int i = 0; i < blockedBy.Count; i++)
                {
                    //BlockedBy += $"({blockedBy.ElementAt(i).Item1 + "," + blockedBy.ElementAt(i).Item2});";
                    blockedByItems.Add(
                        new BlockedByItem
                        {
                            CarCode = blockedBy.ElementAt(i).Item1.ToString(),
                            Type = blockedBy.ElementAt(i).Item2
                        }
                    );
                }
                //BlockedBy = BlockedBy.TrimEnd(';');
                return new CarStateInfo()
                {
                    Code = carCode,
                    Name = singleCar.name,
                    CurrState = carState,
                    IsOnline = isOnline,
                    Battery = singleCar.status.enums.ContainsKey("Soc")
                        ? int.Parse(singleCar.status.enums["Soc"])
                        : 100,
                    Voltage = singleCar.status.enums.ContainsKey("Voltage")
                        ? double.Parse(singleCar.status.enums["Voltage"])
                        : 0,
                    ElectricCurrent = singleCar.status.enums.ContainsKey("ElectricCurrent")
                        ? double.Parse(singleCar.status.enums["ElectricCurrent"])
                        : 0,
                    X = singleCar.x,
                    Y = singleCar.y,
                    Theta = singleCar.th,
                    Speed = singleCar.status.enums.ContainsKey("ActualLeftWheelVelocity")
                        ? double.Parse(
                            SimpleLib.GetCar(carId).status.enums["ActualLeftWheelVelocity"]
                        )
                        : singleCar.speed,
                    //CurrNodeCode = currentSite.fields.ContainsKey("code") ? currentSite.fields["code"] : currentSite.id.ToString(),
                    Load = singleCar.status.enums.TryGetValue("loadStatus", out var statusEnum)
                        ? int.Parse(statusEnum)
                        : 0,
                    CurrNodeCode = currentSite.id.ToString(),
                    StartNodeCode = "0",
                    EndNodeCode = "0",
                    StartEdgeCode = "0",
                    EndEdgeCode = "0",
                    HoldingLocks = singleCar.status.holdingLocks.ToList(),
                    PendingLocks = singleCar.status.pendingLocks.ToList(),
                    BlockedBy = blockedByItems,
                    // BlockingTime = singleCar.status.blockingTime.ToString("yyyy-MM-dd HH:mm:ss"),//没有了
                    TrafficMessage = singleCar.status.TCStat.ToString(),
                    AquiringLock = singleCar.status.aquiringLock,
                    Tasks = taskList,
                    Alarms = alarmsList,
                    StopAccept = singleCar.fields.ContainsKey("StopAccept"),
                    Actions = new List<TaskAction>()
                };
            }
            catch (Exception ex)
            {
                Console.WriteLine($"getCarStateInfo => ex: {ex}");
                return new CarStateInfo();
            }
        }

        public string SwitchCarState(Car car, ref bool isOnline)
        {
            string state = "Stopping";
            if (car.GetLastSite() == -1)
            {
                isOnline = false;
                return state;
            }
            if (Commons.GetVehicleStatus(car)!= VehicleStatus.Offline)
            {
                if (Commons.GetVehicleStatus(car) is VehicleStatus.Normal or VehicleStatus.NeedInit)
                    state = "Stopping"; //Idle
                var lp = car.status.programs.latest;
                if (lp != null)
                {
                    if (
                        lp.status.state >= SimpleCore.Compiler.CarProgram.StatusEnum.Programming
                        && lp.status.state <= SimpleCore.Compiler.CarProgram.StatusEnum.Running
                    )
                    {
                        state = "Running"; //Executing
                    }
                }
                //存在报警信息
                if (car.status.enums.ContainsKey("AlarmInfo"))
                {
                    if (!string.IsNullOrEmpty(car.status.enums["AlarmInfo"]))
                    {
                        state = "Faulting"; //Malfunction
                    }
                }
                if (car.tags.Contains("charging"))
                    state = "Charging";
                isOnline = true;
            }
            else
            {
                isOnline = false;
            }

            return state;
        }

        public string GetDeliveryStatus(TransportDelivery delivery)
        {
            ChainedDeliveryMission.DeliveryStatus status =
                (ChainedDeliveryMission.DeliveryStatus)delivery.GetStatus();

            if (status == ChainedDeliveryMission.DeliveryStatus.Error)
            {
                return "Faulted";
            }
            else if (status == ChainedDeliveryMission.DeliveryStatus.Canceled)
            {
                return "Canceled";
            }
            else if (status == ChainedDeliveryMission.DeliveryStatus.Terminated)
            {
                return "Terminated";
            }
            else if (status == ChainedDeliveryMission.DeliveryStatus.Finished)
            {
                return "Completed";
            }
            else if (status == ChainedDeliveryMission.DeliveryStatus.Putting)
            {
                return "Putting";
            }
            else if (status == ChainedDeliveryMission.DeliveryStatus.Fetching)
            {
                return "Fetching";
            }
            else if (status == ChainedDeliveryMission.DeliveryStatus.Waiting)
            {
                return "Created";
            }
            else
            {
                return "UnKnown";
            }
        }
    }

    internal class MethodInfoDetails
    {
        public string MethodName;

        public string ButtonName;

        public string ButtonDescription;

        public string ParamsHint;

        public List<ParamInfo> ParamsList = new();
    }

    internal class ParamInfo
    {
        public ParamInfo(string name, Type type)
        {
            Name = name;
            Type = type;
        }

        public string Name;
        public Type Type;
    }

    public class HttpPostData
    {
        private HttpClient hc = new HttpClient() { Timeout = TimeSpan.FromSeconds(3) };

        public void UploadSignal(string content)
        {
            try
            {
                //var json = JsonConvert.SerializeObject(new { });
                //var data = new StringContent(json, Encoding.UTF8, "application/json");
                StringContent stringContent = new StringContent(
                    JsonConvert.SerializeObject(content)
                );
                //ApiController._logger.Info($"DeviceNotifyPost:[{stringContent.ToString()}]");

                stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                //hc.Timeout = TimeSpan.FromSeconds(30);
                var task = hc.PostAsync(
                    "http://localhost:20101/api/v1/SecuritySignal/GetSecuritySignal",
                    stringContent
                );
                var responseStr = task.Result.Content.ReadAsStringAsync().Result;
                ResultMsg response = JsonConvert.DeserializeObject<ResultMsg>(responseStr);
            }
            catch (Exception e)
            {
                Diagnosis.Log("DeviceNotifyPost" + ExceptionFormatter.FormatEx(e), $"error", true);
            }
        }

        public void UploadListNode(HashSet<int> contentList)
        {
            try
            {
                /* if (contentList == null || contentList.Count == 0)
                 {
                     throw new ArgumentException("Content list cannot be null or empty.");
                 }*/
                // 序列化List为JSON字符串
                var jsonContent = JsonConvert.SerializeObject(contentList);
                StringContent stringContent = new StringContent(
                    jsonContent,
                    Encoding.UTF8,
                    "application/json"
                );

                // 设置内容类型为application/json
                stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                // 发送POST请求
                var task = hc.PostAsync(
                    "http://localhost:20101/api/v1/Node/NodeListDisable",
                    stringContent
                );
                // 读取响应内容
                var responseStr = task.Result.Content.ReadAsStringAsync().Result;
                // 反序列化响应
                ResultMsg response = JsonConvert.DeserializeObject<ResultMsg>(responseStr);
            }
            catch (Exception e)
            {
                // 记录异常
                Diagnosis.Log("DeviceNotifyPost" + ExceptionFormatter.FormatEx(e), "error", true);
            }
        }
    }

    public class QrSite
    {
        public float X;
        public float Y;
        public float Th;
        public int Tag;
    }

    class ResultMsg
    {
        public string code { get; set; }

        public string reqCode { get; set; }
        public string msg { get; set; }
        public int statu { get; set; }
    }

    public class TrafficRequestModel
    {
        /// <summary>
        /// 区域名称
        /// </summary>
        public string AreaName { get; set; }

        /// <summary>
        /// 控制单位
        /// </summary>
        public string ControllerName { get; set; }

        /// <summary>
        /// 申请占用/释放区域，true为占用，false为释放
        /// </summary>
        public bool IsOccupy { get; set; }
    }
}
