using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http;
using MesServerWork;
using MisDataSaveDate.Helper;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using static MisDataSaveDate.Helper.ApiLogHelper;

namespace MisDataSaveDate
{
    /// <summary>
    /// TCS插拔任务业务处理。PLC自动任务与Web人工任务共用此入口。
    /// </summary>
    public class TCSAGV_BusinessLogic
    {
        private const string TaskTypeCombined = "nav_action_program";
        private const string TaskTypeProgram = "program";

        public static TCSAGV_CallResult DispatchStationTask(string stationCode, string actionType,
            string portCombination, string source, string operatorCode, string parentExternalCode, bool notifyPlc)
        {
            TCSAGV_Config config = ReadConfig(true);
            TCSAGV_PointConfig point = ReadPointConfig(stationCode);
            string normalizedAction = NormalizeAction(actionType);
            string productModel = "";
            string combination;

            if (string.IsNullOrWhiteSpace(portCombination))
            {
                productModel = ReadCurrentProductModel(point.StationCode);
                combination = ReadModelActionCombination(point.LineCode, productModel, normalizedAction);
            }
            else
            {
                combination = NormalizePortCombination(portCombination);
            }

            JArray parameters = new JArray
            {
                new JObject { { "workStation", point.WorkStation } }
            };
            if (combination.Contains("XSD"))
            {
                parameters.Add(new JObject
                {
                    { "programName", normalizedAction == "插" ? point.InsertXsdProgram : point.PullXsdProgram }
                });
            }
            if (combination.Contains("XSE"))
            {
                parameters.Add(new JObject
                {
                    { "programName", normalizedAction == "插" ? point.InsertXseProgram : point.PullXseProgram }
                });
            }

            string externalCode = CreateExternalCode(normalizedAction == "插" ? "PLUG" : "PULL");
            return CreateAndSendTask(config, point, externalCode, parentExternalCode, normalizedAction, "",
                productModel, combination, TaskTypeCombined, parameters.ToString(Formatting.None), source,
                operatorCode, notifyPlc);
        }

        public static TCSAGV_CallResult DispatchSingleStep(string stationCode, string programName,
            string operatorCode, string parentExternalCode)
        {
            TCSAGV_Config config = ReadConfig(true);
            TCSAGV_PointConfig point = ReadPointConfig(stationCode);
            EnsureRobotAtPoint(config, point);
            string normalizedProgram = (programName ?? "").Trim();
            if (!IsConfiguredProgram(point, normalizedProgram))
            {
                throw new Exception("所选programName不属于该工位配置");
            }

            string action = normalizedProgram.Contains("拔") ? "拔-单步" : "插-单步";
            JArray parameters = new JArray
            {
                new JObject { { "programName", normalizedProgram } }
            };
            return CreateAndSendTask(config, point, CreateExternalCode("STEP"), parentExternalCode,
                action, normalizedProgram, "", normalizedProgram.Contains("XSD") ? "XSD" : "XSE",
                TaskTypeProgram, parameters.ToString(Formatting.None),
                "MANUAL", operatorCode, false);
        }

        public static TCSAGV_CallResult RetryTask(string externalCode, string operatorCode)
        {
            DataRow original = ReadTask(externalCode);
            if (!IsFailureStatus(ToInt(original["任务状态"], -1)))
            {
                throw new Exception("仅任务错误状态允许整单重发");
            }
            if (ToBool(original["处理状态"]))
            {
                throw new Exception("失败任务已处理，不能再次重发");
            }
            if (!ToBool(original["已复位"]))
            {
                throw new Exception("请先复位移动机器人再重发任务");
            }

            TCSAGV_Config config = ReadConfig(true);
            TCSAGV_PointConfig point = ReadPointConfig(Convert.ToString(original["MES工位号"]));
            string action = Convert.ToString(original["任务动作"]);
            string programName = Convert.ToString(original["ProgramName"]);
            string productModel = Convert.ToString(original["产品型号"]);
            string combination = Convert.ToString(original["动作组合"]);
            string taskType = Convert.ToString(original["任务类型"]);
            string param = Convert.ToString(original["参数"]);

            return CreateAndSendTask(config, point, CreateExternalCode("RETRY"), externalCode,
                action, programName, productModel, combination, taskType, param, "RETRY", operatorCode, false);
        }

        public static TCSAGV_CallResult CancelTask(string externalCode, string operatorCode)
        {
            if (string.IsNullOrWhiteSpace(externalCode))
            {
                throw new Exception("外部任务编号不能为空");
            }

            TCSAGV_Config config = ReadConfig(true);
            TCSAGV_CallResult result = GetFromTcs(config, "cancelExternalBusinessTask",
                "/api/cancelExternalBusinessTask", new Dictionary<string, string> { { "externalCode", externalCode } });
            if (result.Success)
            {
                SetLocalTaskStatus(externalCode, 3, "已取消", "");
            }
            SaveOperation(externalCode, "", "取消任务", operatorCode, result.RequestText,
                result.ResponseText, result.Success, result.Message);
            return result;
        }

        public static TCSAGV_CallResult StopPendingTasks(string externalCode, string operatorCode)
        {
            TCSAGV_Config config = ReadConfig(true);
            TCSAGV_CallResult result = GetFromTcs(config, "stopExternalBusinessTask",
                "/api/stopExternalBusinessTask", null);
            if (result.Success && !string.IsNullOrWhiteSpace(externalCode))
            {
                DataRow task = ReadTask(externalCode);
                if (ToInt(task["任务状态"], -1) == 0)
                {
                    SetLocalTaskStatus(externalCode, 3, "已停止", "停止全部未开始任务");
                }
            }
            SaveOperation(externalCode, "", "停止未开始任务", operatorCode, result.RequestText,
                result.ResponseText, result.Success, result.Message);
            return result;
        }

        public static TCSAGV_CallResult ResetRobot(string externalCode, string ip, string operatorCode)
        {
            TCSAGV_Config config = ReadConfig(true);
            string robotIp = string.IsNullOrWhiteSpace(ip) ? config.McrIp : ip.Trim();
            if (string.IsNullOrWhiteSpace(robotIp))
            {
                throw new Exception("未配置AGV IP");
            }

            TCSAGV_CallResult result = GetFromTcs(config, "reset", "/api/reset",
                new Dictionary<string, string> { { "ip", robotIp } });
            if (result.Success && !string.IsNullOrWhiteSpace(externalCode))
            {
                try
                {
                    SqlParameter[] parameters =
                    {
                        new SqlParameter("@外部任务编号", externalCode.Trim())
                    };
                    EnsureBusinessSuccess(ExecuteProcedure("XD_TCS_AGV_任务_复位标记", parameters));
                }
                catch (Exception ex)
                {
                    SaveOperation(externalCode, "", "移动机器人复位", operatorCode, result.RequestText,
                        result.ResponseText, false, "TCS复位成功，但MES复位标记失败：" + ex.Message);
                    throw;
                }
            }
            SaveOperation(externalCode, "", "移动机器人复位", operatorCode, result.RequestText,
                result.ResponseText, result.Success, result.Message);
            return result;
        }

        public static TCSAGV_CallResult StopNow(string externalCode, string ip, string operatorCode)
        {
            TCSAGV_Config config = ReadConfig(true);
            string robotIp = string.IsNullOrWhiteSpace(ip) ? config.McrIp : ip.Trim();
            if (string.IsNullOrWhiteSpace(robotIp))
            {
                throw new Exception("未配置AGV IP");
            }

            TCSAGV_CallResult result = GetFromTcs(config, "stopNow", "/api/stopNow",
                new Dictionary<string, string> { { "ip", robotIp } });
            if (result.Success && !string.IsNullOrWhiteSpace(externalCode))
            {
                SetLocalTaskStatus(externalCode, 4, "任务错误", "人工紧急停止");
            }
            SaveOperation(externalCode, "", "紧急停止", operatorCode, result.RequestText,
                result.ResponseText, result.Success, result.Message);
            return result;
        }

        public static TCSAGV_CallResult SyncTaskStatus(string externalCode, string operatorCode)
        {
            TCSAGV_Config config = ReadConfig(true);
            TCSAGV_CallResult result = GetFromTcs(config, "getExternalBusinessTaskStatus",
                "/api/getExternalBusinessTaskStatus", new Dictionary<string, string> { { "externalCode", externalCode } });
            if (result.Success)
            {
                JObject task = FirstResultObject(result.Response);
                if (task != null && task["status"] != null)
                {
                    int status = ToInt(task["status"], -1);
                    if (status >= 0 && status <= 5)
                    {
                        UpdateTaskStatus(externalCode, status,
                            Convert.ToString(task["ip"] ?? ""), Convert.ToString(task["type"] ?? ""),
                            Convert.ToString(task["beginTime"] ?? ""), Convert.ToString(task["endTime"] ?? ""),
                            Convert.ToString(task["remark"] ?? ""));
                    }
                }
            }
            SaveOperation(externalCode, "", "同步任务状态", operatorCode, result.RequestText,
                result.ResponseText, result.Success, result.Message);
            return result;
        }

        public static TCSAGV_CallResult QueryRobotInfo()
        {
            TCSAGV_Config config = ReadConfig(true);
            return QueryRobotInfo(config);
        }

        private static TCSAGV_CallResult QueryRobotInfo(TCSAGV_Config config)
        {
            Dictionary<string, string> query = new Dictionary<string, string>
            {
                { "mcrGroup", config.McrGroup }
            };
            if (!string.IsNullOrWhiteSpace(config.McrIp))
            {
                query.Add("mcrIp", config.McrIp);
            }
            return GetFromTcs(config, "getMcrInfo", "/api/getMcrInfo", query);
        }

        public static void HandleFailure(string externalCode, string operatorCode, string remark, bool notifyPlc)
        {
            DataRow task = ReadTask(externalCode);
            if (!IsFailureStatus(ToInt(task["任务状态"], -1)))
            {
                throw new Exception("仅任务错误状态允许人工处理");
            }
            if (!ToBool(task["已复位"]))
            {
                throw new Exception("请先复位移动机器人再完成人工处理");
            }
            if (string.IsNullOrWhiteSpace(remark))
            {
                throw new Exception("处理说明不能为空");
            }

            if (notifyPlc)
            {
                WritePlcCompletion(task);
            }

            SqlParameter[] parameters =
            {
                new SqlParameter("@外部任务编号", externalCode ?? ""),
                new SqlParameter("@处理人", operatorCode ?? ""),
                new SqlParameter("@处理说明", remark ?? "")
            };
            EnsureBusinessSuccess(ExecuteProcedure("XD_TCS_AGV_任务_人工处理", parameters));
            SaveOperation(externalCode, Convert.ToString(task["MES工位号"]), "失败任务人工处理",
                operatorCode, "", "", true, remark);
        }

        public static string ProcessTaskStatus(string url, [FromBody] JObject jobj)
        {
            string requestText = jobj == null ? "" : jobj.ToString(Formatting.None);
            SaveLog_Interface_Request(url, 2, requestText, out int aid);
            TCSAGV_ApiResponse response;
            try
            {
                if (jobj == null)
                {
                    throw new Exception("请求参数不能为空");
                }
                TCSAGV_TaskStatusPushRequest request = jobj.ToObject<TCSAGV_TaskStatusPushRequest>();
                if (request == null || string.IsNullOrWhiteSpace(request.externalCode))
                {
                    throw new Exception("外部任务编号不能为空");
                }
                int status = ToInt(request.status, -1);
                if (status < 0 || status > 5)
                {
                    throw new Exception("任务状态必须为0至5");
                }

                UpdateTaskStatus(request.externalCode, status, request.ip, request.type,
                    request.beginTime, request.endTime, request.remark);
                response = TCSAGV_ApiResponse.Ok("接收成功", "接收成功");
            }
            catch (Exception ex)
            {
                response = TCSAGV_ApiResponse.Fail(ex.Message);
                SaveMesLog("TCS任务状态推送", ex.Message, MesLogType.ERROR);
            }

            string responseText = JsonConvert.SerializeObject(response);
            SaveLog_Interface_Response(responseText, aid);
            return responseText;
        }

        public static string ProcessPositionPush(string url, [FromBody] JObject jobj)
        {
            string requestText = jobj == null ? "" : jobj.ToString(Formatting.None);
            SaveLog_Interface_Request(url, 2, requestText, out int aid);
            TCSAGV_ApiResponse response;
            try
            {
                if (jobj == null)
                {
                    throw new Exception("请求参数不能为空");
                }
                TCSAGV_PositionPushRequest request = jobj.ToObject<TCSAGV_PositionPushRequest>();
                if (request == null || string.IsNullOrWhiteSpace(request.ip))
                {
                    throw new Exception("机器人IP不能为空");
                }

                SqlParameter[] parameters =
                {
                    new SqlParameter("@机器人IP", request.ip ?? ""),
                    new SqlParameter("@当前站点", request.currentPos ?? ""),
                    new SqlParameter("@目标站点", request.objectivePos ?? ""),
                    new SqlParameter("@原始报文", requestText)
                };
                ExecuteProcedure("XD_TCS_AGV_位置_更新", parameters);
                response = TCSAGV_ApiResponse.Ok("接收成功", "接收成功");
            }
            catch (Exception ex)
            {
                response = TCSAGV_ApiResponse.Fail(ex.Message);
                SaveMesLog("TCS位置推送", ex.Message, MesLogType.ERROR);
            }

            string responseText = JsonConvert.SerializeObject(response);
            SaveLog_Interface_Response(responseText, aid);
            return responseText;
        }

        private static TCSAGV_CallResult CreateAndSendTask(TCSAGV_Config config, TCSAGV_PointConfig point,
            string externalCode, string parentExternalCode, string action, string programName,
            string productModel, string combination, string taskType, string param, string source,
            string operatorCode, bool notifyPlc)
        {
            TCSAGV_TaskRequest request = new TCSAGV_TaskRequest
            {
                externalCode = externalCode,
                type = taskType,
                priority = config.DefaultPriority,
                param = param,
                mcrgroup = config.McrGroup,
                mcrip = config.McrIp,
                operatoruserid = config.OperatorUserId
            };

            SqlParameter[] createParameters =
            {
                new SqlParameter("@外部任务编号", externalCode),
                new SqlParameter("@原任务编号", parentExternalCode ?? ""),
                new SqlParameter("@MES工位号", point.StationCode),
                new SqlParameter("@任务动作", action),
                new SqlParameter("@产品型号", productModel ?? ""),
                new SqlParameter("@动作组合", combination ?? ""),
                new SqlParameter("@ProgramName", programName ?? ""),
                new SqlParameter("@任务类型", taskType),
                new SqlParameter("@参数", param),
                new SqlParameter("@优先级", config.DefaultPriority),
                new SqlParameter("@机器人组", config.McrGroup ?? ""),
                new SqlParameter("@机器人IP", config.McrIp ?? ""),
                new SqlParameter("@来源", source ?? ""),
                new SqlParameter("@操作人", operatorCode ?? ""),
                new SqlParameter("@是否通知PLC", notifyPlc)
            };
            EnsureBusinessSuccess(ExecuteProcedure("XD_TCS_AGV_任务_创建", createParameters));

            TCSAGV_CallResult result;
            try
            {
                result = PostToTcs(config, "createExternalBusinessTask", "/api/createExternalBusinessTask", request);
            }
            catch (Exception ex)
            {
                UpdateDispatchResult(externalCode, JsonConvert.SerializeObject(request), "", false, ex.Message);
                SaveOperation(externalCode, point.StationCode, "下发" + action + "任务", operatorCode,
                    JsonConvert.SerializeObject(request), "", false, ex.Message);
                throw;
            }

            UpdateDispatchResult(externalCode, result.RequestText, result.ResponseText, result.Success,
                result.Success ? "" : result.Message);
            SaveOperation(externalCode, point.StationCode, "下发" + action + "任务", operatorCode,
                result.RequestText, result.ResponseText, result.Success, result.Message);
            result.ExternalCode = externalCode;
            return result;
        }

        private static void UpdateTaskStatus(string externalCode, int status, string ip, string type,
            string beginTime, string endTime, string remark)
        {
            SqlParameter[] parameters =
            {
                new SqlParameter("@外部任务编号", externalCode ?? ""),
                new SqlParameter("@任务状态", status),
                new SqlParameter("@机器人IP", ip ?? ""),
                new SqlParameter("@任务类型", type ?? ""),
                new SqlParameter("@开始时间", beginTime ?? ""),
                new SqlParameter("@结束时间", endTime ?? ""),
                new SqlParameter("@备注", remark ?? "")
            };
            DataTable result = ExecuteProcedure("XD_TCS_AGV_任务_状态更新", parameters);
            EnsureBusinessSuccess(result);

            if (status == 2 && result.Rows.Count > 0 && ToBool(result.Rows[0]["是否通知PLC"])
                && !ToBool(result.Rows[0]["PLC已通知"]))
            {
                DataRow task = ReadTask(externalCode);
                WritePlcCompletion(task);
                SqlParameter[] notified = { new SqlParameter("@外部任务编号", externalCode) };
                ExecuteProcedure("XD_TCS_AGV_任务_PLC通知完成", notified);
            }
        }

        private static bool IsFailureStatus(int status)
        {
            return status == 4 || status == 5;
        }

        private static void WritePlcCompletion(DataRow task)
        {
            string stationCode = Convert.ToString(task["MES工位号"]);
            string action = Convert.ToString(task["任务动作"]);
            int tagCode = action.StartsWith("插", StringComparison.Ordinal) ? 400
                : action.StartsWith("拔", StringComparison.Ordinal) ? 401 : 0;
            if (tagCode == 0)
            {
                throw new Exception("任务动作无法确定PLC完成码");
            }
            if (!MIS_BASE.WritePLC(tagCode, stationCode, true))
            {
                throw new Exception("任务完成但PLC完成信号写入失败");
            }
            SaveMesLog(stationCode, "TCS任务完成，已写入PLC功能码" + tagCode, MesLogType.INFO);
        }

        private static TCSAGV_Config ReadConfig(bool requireEnabled)
        {
            DataTable table = ExecuteProcedure("XD_TCS_AGV_配置_获取", new SqlParameter[0]);
            if (table.Rows.Count == 0)
            {
                throw new Exception("未配置TCS参数");
            }
            DataRow row = table.Rows[0];
            TCSAGV_Config config = new TCSAGV_Config
            {
                BaseUrl = Convert.ToString(row["TCS_BaseUrl"]),
                Enabled = Convert.ToString(row["TCS_Enabled"]) == "1",
                McrGroup = Convert.ToString(row["McrGroup"]),
                McrIp = Convert.ToString(row["McrIp"]),
                OperatorUserId = Convert.ToString(row["TCS_OperatorUserId"]),
                DefaultPriority = ToInt(row["DefaultPriority"], 1),
                HttpTimeoutSeconds = ToInt(row["HttpTimeoutSeconds"], 15)
            };
            if (string.IsNullOrWhiteSpace(config.BaseUrl))
            {
                throw new Exception("未配置TCS服务地址");
            }
            if (string.IsNullOrWhiteSpace(config.OperatorUserId))
            {
                throw new Exception("未配置TCS任务状态推送标识");
            }
            if (requireEnabled && !config.Enabled)
            {
                throw new Exception("TCS真实下发开关未启用，请先确认现场地址和AGV IP");
            }
            return config;
        }

        private static TCSAGV_PointConfig ReadPointConfig(string stationCode)
        {
            if (string.IsNullOrWhiteSpace(stationCode))
            {
                throw new Exception("MES工位号不能为空");
            }
            SqlParameter[] parameters = { new SqlParameter("@MES工位号", stationCode.Trim()) };
            DataTable table = ExecuteProcedure("XD_TCS_AGV_点位配置_查询", parameters);
            if (table.Rows.Count == 0)
            {
                throw new Exception("MES工位未配置TCS站点和programName");
            }
            DataRow row = table.Rows[0];
            return new TCSAGV_PointConfig
            {
                LineCode = Convert.ToString(row["产线代码"]),
                StationCode = Convert.ToString(row["MES工位号"]),
                PositionName = Convert.ToString(row["现场位置"]),
                WorkStation = Convert.ToString(row["WorkStation"]),
                InsertXsdProgram = Convert.ToString(row["插XSDProgramName"]),
                InsertXseProgram = Convert.ToString(row["插XSEProgramName"]),
                PullXsdProgram = Convert.ToString(row["拔XSDProgramName"]),
                PullXseProgram = Convert.ToString(row["拔XSEProgramName"])
            };
        }

        private static string ReadCurrentProductModel(string stationCode)
        {
            SqlParameter[] parameters = { new SqlParameter("@MES工位号", stationCode) };
            DataTable table = ExecuteProcedure("XD_TCS_AGV_库位产品_查询", parameters);
            string productModel = table.Rows.Count == 0 ? "" : Convert.ToString(table.Rows[0]["产品型号"]);
            if (string.IsNullOrWhiteSpace(productModel))
            {
                throw new Exception("工位" + stationCode + "未获取到当前产品型号");
            }
            return productModel.Trim();
        }

        private static string ReadModelActionCombination(string lineCode, string productModel, string action)
        {
            SqlParameter[] parameters =
            {
                new SqlParameter("@产线代码", lineCode),
                new SqlParameter("@产品型号", productModel),
                new SqlParameter("@任务动作", action)
            };
            DataTable table = ExecuteProcedure("XD_TCS_AGV_型号动作映射_查询", parameters);
            if (table.Rows.Count == 0)
            {
                throw new Exception("产品型号" + productModel + "未配置" + action + "动作组合");
            }
            return Convert.ToString(table.Rows[0]["动作组合"]);
        }

        private static DataRow ReadTask(string externalCode)
        {
            if (string.IsNullOrWhiteSpace(externalCode))
            {
                throw new Exception("外部任务编号不能为空");
            }
            SqlParameter[] parameters = { new SqlParameter("@外部任务编号", externalCode.Trim()) };
            DataTable table = ExecuteProcedure("XD_TCS_AGV_任务_获取", parameters);
            if (table.Rows.Count == 0)
            {
                throw new Exception("外部任务不存在");
            }
            return table.Rows[0];
        }

        private static void EnsureRobotAtPoint(TCSAGV_Config config, TCSAGV_PointConfig point)
        {
            TCSAGV_CallResult result = QueryRobotInfo(config);
            if (!result.Success)
            {
                throw new Exception("查询AGV实时位置失败：" + result.Message);
            }
            JObject robot = FirstResultObject(result.Response);
            if (robot == null)
            {
                throw new Exception("未查询到AGV状态，不能执行单步任务");
            }
            if (ToInt(robot["status"], -1) == 4)
            {
                throw new Exception("AGV当前未连接，不能执行单步任务");
            }
            string currentPosition = Convert.ToString(robot["currentPos"]);
            if (string.IsNullOrWhiteSpace(currentPosition))
            {
                throw new Exception("未获取到AGV当前位置，不能执行单步任务");
            }
            if (!string.Equals(currentPosition, point.WorkStation, StringComparison.OrdinalIgnoreCase))
            {
                throw new Exception("AGV当前位置" + currentPosition + "与所选站点" + point.WorkStation + "不一致");
            }
        }

        private static void UpdateDispatchResult(string externalCode, string requestText, string responseText,
            bool success, string errorMessage)
        {
            SqlParameter[] parameters =
            {
                new SqlParameter("@外部任务编号", externalCode ?? ""),
                new SqlParameter("@请求报文", requestText ?? ""),
                new SqlParameter("@响应报文", responseText ?? ""),
                new SqlParameter("@是否成功", success),
                new SqlParameter("@错误信息", errorMessage ?? "")
            };
            ExecuteProcedure("XD_TCS_AGV_任务_下发结果更新", parameters);
        }

        private static void SetLocalTaskStatus(string externalCode, int status, string statusText, string errorMessage)
        {
            SqlParameter[] parameters =
            {
                new SqlParameter("@外部任务编号", externalCode ?? ""),
                new SqlParameter("@任务状态", status),
                new SqlParameter("@状态说明", statusText ?? ""),
                new SqlParameter("@错误信息", errorMessage ?? "")
            };
            ExecuteProcedure("XD_TCS_AGV_任务_本地状态设置", parameters);
        }

        private static void SaveOperation(string externalCode, string stationCode, string operationType,
            string operatorCode, string requestText, string responseText, bool success, string message)
        {
            try
            {
                SqlParameter[] parameters =
                {
                    new SqlParameter("@外部任务编号", externalCode ?? ""),
                    new SqlParameter("@MES工位号", stationCode ?? ""),
                    new SqlParameter("@操作类型", operationType ?? ""),
                    new SqlParameter("@操作人", operatorCode ?? ""),
                    new SqlParameter("@请求报文", requestText ?? ""),
                    new SqlParameter("@响应报文", responseText ?? ""),
                    new SqlParameter("@是否成功", success),
                    new SqlParameter("@操作结果", message ?? "")
                };
                ExecuteProcedure("XD_TCS_AGV_操作记录_增加", parameters);
            }
            catch (Exception ex)
            {
                SaveMesLog("TCS操作记录", ex.Message, MesLogType.ERROR);
            }
        }

        private static TCSAGV_CallResult PostToTcs(TCSAGV_Config config, string interfaceName,
            string path, object request)
        {
            string url = config.BaseUrl.TrimEnd('/') + path;
            string requestText = JsonConvert.SerializeObject(request);
            SaveLog_Interface_Request("TCS_" + interfaceName, 1, requestText, out int aid);
            string responseText;
            using (HttpClient client = CreateHttpClient(config))
            using (StringContent content = new StringContent(requestText, Encoding.UTF8, "application/json"))
            {
                HttpResponseMessage response = client.PostAsync(url, content).GetAwaiter().GetResult();
                responseText = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                if (string.IsNullOrWhiteSpace(responseText) && !response.IsSuccessStatusCode)
                {
                    responseText = "HTTP " + (int)response.StatusCode;
                }
            }
            SaveLog_Interface_Response(responseText, aid);
            return ParseCallResult(requestText, responseText);
        }

        private static TCSAGV_CallResult GetFromTcs(TCSAGV_Config config, string interfaceName,
            string path, IDictionary<string, string> query)
        {
            StringBuilder url = new StringBuilder(config.BaseUrl.TrimEnd('/') + path);
            JObject request = new JObject();
            if (query != null && query.Count > 0)
            {
                url.Append('?');
                bool first = true;
                foreach (KeyValuePair<string, string> item in query)
                {
                    if (!first) url.Append('&');
                    first = false;
                    url.Append(HttpUtility.UrlEncode(item.Key));
                    url.Append('=');
                    url.Append(HttpUtility.UrlEncode(item.Value ?? ""));
                    request[item.Key] = item.Value ?? "";
                }
            }

            string requestText = request.ToString(Formatting.None);
            bool skipInterfaceLog = string.Equals(interfaceName, "getMcrInfo",
                StringComparison.OrdinalIgnoreCase);
            int aid = 0;
            if (!skipInterfaceLog)
            {
                SaveLog_Interface_Request("TCS_" + interfaceName, 1, requestText, out aid);
            }
            string responseText;
            using (HttpClient client = CreateHttpClient(config))
            {
                HttpResponseMessage response = client.GetAsync(url.ToString()).GetAwaiter().GetResult();
                responseText = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
                if (string.IsNullOrWhiteSpace(responseText) && !response.IsSuccessStatusCode)
                {
                    responseText = "HTTP " + (int)response.StatusCode;
                }
            }
            if (!skipInterfaceLog)
            {
                SaveLog_Interface_Response(responseText, aid);
            }
            return ParseCallResult(requestText, responseText);
        }

        private static HttpClient CreateHttpClient(TCSAGV_Config config)
        {
            return new HttpClient
            {
                Timeout = TimeSpan.FromSeconds(config.HttpTimeoutSeconds > 0 ? config.HttpTimeoutSeconds : 15)
            };
        }

        private static TCSAGV_CallResult ParseCallResult(string requestText, string responseText)
        {
            JObject response;
            try
            {
                response = JObject.Parse(responseText ?? "");
            }
            catch (Exception ex)
            {
                return new TCSAGV_CallResult
                {
                    Success = false,
                    Code = 500,
                    Message = "TCS返回非JSON响应：" + ex.Message,
                    RequestText = requestText,
                    ResponseText = responseText,
                    Response = null
                };
            }

            bool successFlag = false;
            bool hasSuccessFlag = response["success"] != null;
            if (hasSuccessFlag)
            {
                bool.TryParse(Convert.ToString(response["success"]), out successFlag);
            }
            int code = ToInt(response["code"], successFlag ? 200 : 500);
            bool success = hasSuccessFlag ? successFlag && code == 200 : code == 200;
            string message = Convert.ToString(response["message"] ?? response["msg"] ?? response["result"] ?? "");
            return new TCSAGV_CallResult
            {
                Success = success,
                Code = code,
                Message = message,
                RequestText = requestText,
                ResponseText = responseText,
                Response = response
            };
        }

        private static JObject FirstResultObject(JObject response)
        {
            if (response == null || response["result"] == null) return null;
            JToken result = response["result"];
            if (result.Type == JTokenType.Array)
            {
                JArray array = (JArray)result;
                return array.Count > 0 ? array[0] as JObject : null;
            }
            return result as JObject;
        }

        private static DataTable ExecuteProcedure(string procedureName, SqlParameter[] parameters)
        {
            SqlParameter[] procedureParameters = parameters ?? new SqlParameter[0];
            DataLinkMesWork2.DataAccess2.ExecuteStoredProcedure(procedureName, ref procedureParameters,
                out DataTable table, out string errorMessage);
            if (!string.IsNullOrWhiteSpace(errorMessage))
            {
                throw new Exception(errorMessage);
            }
            return table ?? new DataTable();
        }

        private static void EnsureBusinessSuccess(DataTable table)
        {
            if (table == null || table.Rows.Count == 0)
            {
                throw new Exception("数据库未返回业务结果");
            }
            if (ToInt(table.Rows[0]["result"], 0) != 1)
            {
                string message = table.Columns.Contains("msg") ? Convert.ToString(table.Rows[0]["msg"]) : "业务操作失败";
                throw new Exception(message);
            }
        }

        private static string NormalizeAction(string actionType)
        {
            string value = (actionType ?? "").Trim();
            if (value == "插" || value.Equals("plug", StringComparison.OrdinalIgnoreCase)) return "插";
            if (value == "拔" || value.Equals("pull", StringComparison.OrdinalIgnoreCase)) return "拔";
            throw new Exception("任务动作只支持插或拔");
        }

        private static string NormalizePortCombination(string portCombination)
        {
            string value = (portCombination ?? "").Trim().ToUpperInvariant();
            if (value == "XSD" || value == "XSE" || value == "XSD+XSE") return value;
            throw new Exception("动作组合只支持XSD、XSE或XSD+XSE");
        }

        private static bool IsConfiguredProgram(TCSAGV_PointConfig point, string programName)
        {
            return programName == point.InsertXsdProgram || programName == point.InsertXseProgram
                || programName == point.PullXsdProgram || programName == point.PullXseProgram;
        }

        private static string CreateExternalCode(string prefix)
        {
            return "XD_" + prefix + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_"
                + Guid.NewGuid().ToString("N").Substring(0, 6).ToUpperInvariant();
        }

        private static int ToInt(object value, int defaultValue)
        {
            int result;
            return int.TryParse(Convert.ToString(value), out result) ? result : defaultValue;
        }

        private static bool ToBool(object value)
        {
            string text = Convert.ToString(value);
            return text == "1" || text.Equals("true", StringComparison.OrdinalIgnoreCase);
        }
    }
}
