using DataLinkMesWork2;
using MisDataFunDll;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using System.Web.Http;
using static MisDataSaveDate.Helper.ApiLogHelper;

namespace ExternalDataSync.MOM
{
    public static class DewPointDataHandler
    {
        private const string DefaultFlagValue = "0";

        public static string OnlineDewPointResultData(string url, [FromBody] JObject jobj)
        {
            return ExecuteRequest<ResultDataRequest>(url, jobj, "接收露点仪测试结果数据", request =>
            {
                string msgId = RequireText(request.MsgId, "MsgId");
                string deviceCode = RequireText(request.DeviceCode, "DeviceCode");
                string testDateText = RequireText(request.TestDate, "TestDate");
                if (request.TestItems == null || request.TestItems.Count == 0)
                {
                    throw new Exception("参数TestItems为空！");
                }

                DateTime testDate = ParseDate(testDateText, "TestDate");
                DateTime? startTime = CombineDateAndTime(testDate, request.StartTime, "StartTime");
                DateTime? endTime = CombineDateAndTime(testDate, request.EndTime, "EndTime");
                DateTime actionTime = startTime ?? endTime ?? testDate;
                string serialNumber = CleanText(request.SectionNo);
                string userNumber = GetDefaultUser(request.UserNumber);
                int overallQualityMark = request.IsQualified == false ? 2 : 1;

                int idTagCf = SaveMeasurementIndex(serialNumber, deviceCode, userNumber, actionTime, overallQualityMark);

                foreach (MeasurementDetail detail in BuildResultDetails(request, overallQualityMark))
                {
                    SaveMeasurementDetail(idTagCf, serialNumber, deviceCode, detail);
                }

                SaveQualityInterfaceRecord(deviceCode, serialNumber);
                return msgId;
            });
        }

        public static string OnlineDewPointTechnologyData(string url, [FromBody] JObject jobj)
        {
            return ExecuteRequest<TechnologyDataRequest>(url, jobj, "接收露点仪工艺采集数据", request =>
            {
                string msgId = RequireText(request.MsgId, "MsgId");
                string deviceCode = RequireText(request.DeviceCode, "DeviceCode");
                string serialNumber = CleanText(request.SerialNumber);
                string userNumber = GetDefaultUser(request.UserNumber);
                DateTime actionTime = ParseDateTimeOrNow(request.CreateTime, "CreateTime");

                int idTagCf = SaveMeasurementIndex(serialNumber, deviceCode, userNumber, actionTime, 1);

                foreach (MeasurementDetail detail in BuildTechnologyDetails(request))
                {
                    SaveMeasurementDetail(idTagCf, serialNumber, deviceCode, detail);
                }

                SaveQualityInterfaceRecord(deviceCode, serialNumber);
                return msgId;
            });
        }

        public static string OnlineDewPointUseData(string url, [FromBody] JObject jobj)
        {
            return ExecuteRequest<EquipmentUseRequest>(url, jobj, "接收露点仪设备使用情况数据", request =>
            {
                string msgId = RequireText(request.MsgId, "MsgId");
                string deviceCode = RequireText(request.DeviceCode, "DeviceCode");
                DateTime testDate = ParseDate(RequireText(request.TestDate, "TestDate"), "TestDate");
                int? durationMinutes = ParseNullableInt(request.DurationMinutes, "DurationMinutes");

                SqlParameter[] parameters = new SqlParameter[]
                {
                    new SqlParameter("@Device", ToDbValue(deviceCode, 50)),
                    new SqlParameter("@WorkDate", testDate.Date),
                    new SqlParameter("@Onhours", durationMinutes.HasValue ? (object)durationMinutes.Value : DBNull.Value),
                    new SqlParameter("@Workhours", durationMinutes.HasValue ? (object)durationMinutes.Value : DBNull.Value),
                    new SqlParameter("@Powerused", DBNull.Value),
                    new SqlParameter("@Flag", ToDbValue(CleanText(request.Flag2), 10, DefaultFlagValue))
                };

                ExecuteStoredProcedureOrThrow("EquipmentUse_Backup_TestDeviceAdd", ref parameters);
                return msgId;
            });
        }

        public static string OnlineDewPointStatusData(string url, [FromBody] JObject jobj)
        {
            return ExecuteRequest<EquipmentStatusRequest>(url, jobj, "接收露点仪设备状态数据", request =>
            {
                string msgId = RequireText(request.MsgId, "MsgId");
                string deviceCode = RequireText(request.DeviceCode, "DeviceCode");
                string status = RequireText(request.Status, "Status");
                string statusCode = RequireText(request.StatusCode, "StatusCode");
                DateTime statusTime = ParseDateTime(RequireText(request.StatusTime, "StatusTime"), "StatusTime");

                SqlParameter[] parameters = new SqlParameter[]
                {
                    new SqlParameter("@DeviceCode", ToDbValue(deviceCode, 20)),
                    new SqlParameter("@DeviceStatus", ToDbValue(status, 10)),
                    new SqlParameter("@StatusTime", statusTime),
                    new SqlParameter("@StatusCode", ToDbValue(statusCode, 4)),
                    new SqlParameter("@MalfunctionCode", ToNullableDbValue(request.FaultInfo == null ? string.Empty : request.FaultInfo.FaultCode, 4)),
                    new SqlParameter("@MalfunctionName", ToNullableDbValue(request.FaultInfo == null ? string.Empty : request.FaultInfo.FaultName, 40)),
                    new SqlParameter("@Malfunctionexplain", ToNullableDbValue(request.FaultInfo == null ? string.Empty : request.FaultInfo.FaultDescription, 40)),
                    new SqlParameter("@Flag", ToDbValue(CleanText(request.Flag3), 1, DefaultFlagValue)),
                    new SqlParameter("@Remark", DBNull.Value),
                    new SqlParameter("@alarmRemove", DBNull.Value)
                };

                ExecuteStoredProcedureOrThrow("EquipmentStatus_Backup_TestDeviceAdd", ref parameters);
                return msgId;
            });
        }

        private static string ExecuteRequest<TRequest>(string url, JObject jobj, string logTitle, Func<TRequest, string> executor)
        {
            OnlineCheckDataResponse result = new OnlineCheckDataResponse
            {
                Code = "200",
                Message = "",
                MsgId = "",
                Data = ""
            };

            if (jobj == null)
            {
                result.Code = "500";
                result.Message = "参数格式不正确！";
                string invalidText = JsonConvert.SerializeObject(result);
                MyLog4Net.MyLogHelper.Info(logTitle + "_res", invalidText);
                return invalidText;
            }

            string requestText = jobj.ToString();
            SaveLog_Interface_Request(url, 2, requestText, out int aid);

            try
            {
                TRequest request = JsonConvert.DeserializeObject<TRequest>(requestText);
                if (request == null)
                {
                    throw new Exception("请求体反序列化失败！");
                }

                result.MsgId = executor(request);
            }
            catch (Exception err)
            {
                result.Code = "500";
                result.Message = err.Message;
            }

            string responseText = JsonConvert.SerializeObject(result);
            SaveLog_Interface_Response(responseText, aid);
            MyLog4Net.MyLogHelper.Info(logTitle + "_res", responseText);
            return responseText;
        }

        private static List<MeasurementDetail> BuildResultDetails(ResultDataRequest request, int overallQualityMark)
        {
            List<MeasurementDetail> details = new List<MeasurementDetail>();

            for (int i = 0; i < request.TestItems.Count; i++)
            {
                ResultTestItem item = request.TestItems[i];
                if (item == null)
                {
                    continue;
                }

                string itemName = RequireText(item.ItemName, "TestItems[" + i + "].ItemName");
                details.Add(new MeasurementDetail
                {
                    TagId = itemName,
                    MeasurementName = itemName,
                    TagValue = GetTokenText(item.MeasuredValue),
                    QualityMark = MapQualityMark(item.QualityMark, overallQualityMark),
                    StandardValue = GetTokenText(item.SpecifiedValue),
                    Unit = CleanText(item.Unit)
                });
            }

            // Environment 暂时保留字段，但当前不参与入库。
            return details;
        }

        private static List<MeasurementDetail> BuildTechnologyDetails(TechnologyDataRequest request)
        {
            List<MeasurementDetail> details = new List<MeasurementDetail>();

            AddTechnologyDetail(details, "CheckData", request.CheckData);
            AddTechnologyDetail(details, "TechnologyData", request.TechnologyData);

            if (details.Count == 0)
            {
                throw new Exception("参数CheckData和TechnologyData均为空！");
            }

            return details;
        }

        private static void AddTechnologyDetail(List<MeasurementDetail> details, string fieldName, string fieldValue)
        {
            string value = CleanText(fieldValue);
            if (string.IsNullOrWhiteSpace(value))
            {
                return;
            }

            details.Add(new MeasurementDetail
            {
                TagId = fieldName,
                MeasurementName = fieldName,
                TagValue = value,
                QualityMark = 1,
                StandardValue = "",
                Unit = ""
            });
        }

        private static int SaveMeasurementIndex(string serialNumber, string deviceCode, string userNumber, DateTime actionTime, int qualityMark)
        {
            SqlParameter[] parameters = new SqlParameter[]
            {
                new SqlParameter("@EngineID", ToNullableDbValue(serialNumber, 100)),
                new SqlParameter("@工位号", ToDbValue(deviceCode, 50)),
                new SqlParameter("@操作者工号", ToDbValue(userNumber, 50, "AUTO")),
                new SqlParameter("@扫码时间", actionTime),
                new SqlParameter("@合格标志", qualityMark),
                new SqlParameter("@Id_tagCF", SqlDbType.Int) { Direction = ParameterDirection.Output }
            };

            ExecuteStoredProcedureOrThrow("测量数据合格索引_增加_测试设备", ref parameters);

            if (parameters[5].Value == null || parameters[5].Value == DBNull.Value)
            {
                throw new Exception("测量数据合格索引_增加_测试设备 未返回Id_tagCF！");
            }

            return Convert.ToInt32(parameters[5].Value);
        }

        private static void SaveMeasurementDetail(int idTagCf, string serialNumber, string deviceCode, MeasurementDetail detail)
        {
            SqlParameter[] parameters = new SqlParameter[]
            {
                new SqlParameter("@Id_tagCF", idTagCf),
                new SqlParameter("@EngineID", ToNullableDbValue(serialNumber, 100)),
                new SqlParameter("@TagID", ToDbValue(detail.TagId, 50)),
                new SqlParameter("@TagValue", ToDbValue(detail.TagValue, 100)),
                new SqlParameter("@IsGoodBad", detail.QualityMark),
                new SqlParameter("@工位号", ToDbValue(deviceCode, 50)),
                new SqlParameter("@理论值", ToDbValue(detail.StandardValue, 50)),
                new SqlParameter("@上限值", ToDbValue(string.Empty, 50)),
                new SqlParameter("@下限值", ToDbValue(string.Empty, 50)),
                new SqlParameter("@测量项目", ToDbValue(detail.MeasurementName, 50)),
                new SqlParameter("@测量单位", ToDbValue(detail.Unit, 50))
            };

            ExecuteStoredProcedureOrThrow("测量数据合格_增加_测试设备", ref parameters);
        }

        private static void SaveQualityInterfaceRecord(string deviceCode, string serialNumber)
        {
            if (!string.IsNullOrWhiteSpace(deviceCode) && !string.IsNullOrWhiteSpace(serialNumber))
            {
                MisDataFun.SaveQualityInterfaceData(deviceCode, serialNumber);
            }
        }

        private static int MapQualityMark(int? sourceQualityMark, int defaultQualityMark)
        {
            if (!sourceQualityMark.HasValue)
            {
                return defaultQualityMark;
            }

            if (sourceQualityMark.Value == 0)
            {
                return 1;
            }

            if (sourceQualityMark.Value == 1)
            {
                return 2;
            }

            return sourceQualityMark.Value;
        }

        private static int? ParseNullableInt(JToken token, string fieldName)
        {
            string text = GetTokenText(token);
            if (string.IsNullOrWhiteSpace(text))
            {
                return null;
            }

            if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out int result) ||
                int.TryParse(text, NumberStyles.Integer, CultureInfo.CurrentCulture, out result))
            {
                return result;
            }

            throw new Exception("参数" + fieldName + "格式不正确！");
        }

        private static DateTime ParseDate(string text, string fieldName)
        {
            if (DateTime.TryParseExact(text, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result) ||
                DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out result) ||
                DateTime.TryParse(text, CultureInfo.CurrentCulture, DateTimeStyles.None, out result))
            {
                return result.Date;
            }

            throw new Exception("参数" + fieldName + "格式不正确！");
        }

        private static DateTime ParseDateTime(string text, string fieldName)
        {
            if (DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result) ||
                DateTime.TryParse(text, CultureInfo.CurrentCulture, DateTimeStyles.None, out result))
            {
                return result;
            }

            throw new Exception("参数" + fieldName + "格式不正确！");
        }

        private static DateTime ParseDateTimeOrNow(string text, string fieldName)
        {
            string value = CleanText(text);
            if (string.IsNullOrWhiteSpace(value))
            {
                return DateTime.Now;
            }

            return ParseDateTime(value, fieldName);
        }

        private static DateTime? CombineDateAndTime(DateTime date, string timeText, string fieldName)
        {
            string text = CleanText(timeText);
            if (string.IsNullOrWhiteSpace(text))
            {
                return null;
            }

            if (TimeSpan.TryParse(text, CultureInfo.InvariantCulture, out TimeSpan timePart) ||
                TimeSpan.TryParse(text, CultureInfo.CurrentCulture, out timePart))
            {
                return date.Date.Add(timePart);
            }

            throw new Exception("参数" + fieldName + "格式不正确！");
        }

        private static string RequireText(string value, string fieldName)
        {
            string text = CleanText(value);
            if (string.IsNullOrWhiteSpace(text))
            {
                throw new Exception("参数" + fieldName + "为空！");
            }

            return text;
        }

        private static string RequireText(JToken value, string fieldName)
        {
            string text = GetTokenText(value);
            if (string.IsNullOrWhiteSpace(text))
            {
                throw new Exception("参数" + fieldName + "为空！");
            }

            return text;
        }

        private static string CleanText(string value)
        {
            return value == null ? string.Empty : value.Trim();
        }

        private static string GetDefaultUser(string userNumber)
        {
            string value = CleanText(userNumber);
            return string.IsNullOrWhiteSpace(value) ? "AUTO" : value;
        }

        private static string GetTokenText(JToken token)
        {
            return token == null || token.Type == JTokenType.Null ? string.Empty : token.ToString().Trim();
        }

        private static object ToDbValue(string value, int maxLength)
        {
            return ToDbValue(value, maxLength, string.Empty);
        }

        private static object ToDbValue(string value, int maxLength, string defaultValue)
        {
            string text = CleanText(value);
            if (string.IsNullOrWhiteSpace(text))
            {
                text = defaultValue ?? string.Empty;
            }

            return text.Length > maxLength ? text.Substring(0, maxLength) : text;
        }

        private static object ToNullableDbValue(string value, int maxLength)
        {
            string text = CleanText(value);
            if (string.IsNullOrWhiteSpace(text))
            {
                return DBNull.Value;
            }

            return text.Length > maxLength ? text.Substring(0, maxLength) : text;
        }

        private static void ExecuteStoredProcedureOrThrow(string procedureName, ref SqlParameter[] parameters)
        {
            DataAccess2.ExecuteStoredProcedure(procedureName, ref parameters, out string errorMessage);
            if (!string.IsNullOrWhiteSpace(errorMessage))
            {
                throw new Exception(errorMessage);
            }
        }

        private sealed class ResultDataRequest
        {
            public string DeviceCode { get; set; } = string.Empty;
            public string EndTime { get; set; } = string.Empty;
            public ResultEnvironment Environment { get; set; } = new ResultEnvironment();
            public bool? IsQualified { get; set; }
            public JToken MsgId { get; set; }
            public JToken PowerUsed { get; set; }
            public string SectionNo { get; set; } = string.Empty;
            public string StartTime { get; set; } = string.Empty;
            public string TestDate { get; set; } = string.Empty;
            public List<ResultTestItem> TestItems { get; set; } = new List<ResultTestItem>();
            public string UserNumber { get; set; } = string.Empty;
        }

        private sealed class ResultEnvironment
        {
            public JToken Humidity { get; set; }
            public JToken Temperature { get; set; }
        }

        private sealed class ResultTestItem
        {
            public string ItemName { get; set; } = string.Empty;
            public JToken MeasuredValue { get; set; }
            public int? QualityMark { get; set; }
            public JToken SpecifiedValue { get; set; }
            public string Unit { get; set; } = string.Empty;
        }

        private sealed class TechnologyDataRequest
        {
            public string CheckData { get; set; } = string.Empty;
            public string CreateTime { get; set; } = string.Empty;
            public string DeviceCode { get; set; } = string.Empty;
            public string Flag { get; set; } = string.Empty;
            public string MsgId { get; set; } = string.Empty;
            public string PowerUsed { get; set; } = string.Empty;
            public string SerialNumber { get; set; } = string.Empty;
            public string TechnologyData { get; set; } = string.Empty;
            public string UserNumber { get; set; } = string.Empty;
        }

        private sealed class EquipmentUseRequest
        {
            public string CreateTime { get; set; } = string.Empty;
            public string DeviceCode { get; set; } = string.Empty;
            public JToken DurationMinutes { get; set; }
            public string Flag2 { get; set; } = string.Empty;
            public JToken MsgId { get; set; }
            public string StartTime { get; set; } = string.Empty;
            public string TestDate { get; set; } = string.Empty;
        }

        private sealed class EquipmentStatusRequest
        {
            public string CreateTime { get; set; } = string.Empty;
            public string DeviceCode { get; set; } = string.Empty;
            public FaultInfo FaultInfo { get; set; } = new FaultInfo();
            public JToken MsgId { get; set; }
            public string Status { get; set; } = string.Empty;
            public string StatusCode { get; set; } = string.Empty;
            public string StatusTime { get; set; } = string.Empty;
            public string Flag3 { get; set; } = string.Empty;
        }

        private sealed class FaultInfo
        {
            public string FaultCode { get; set; } = string.Empty;
            public string FaultDescription { get; set; } = string.Empty;
            public string FaultName { get; set; } = string.Empty;
        }

        private sealed class MeasurementDetail
        {
            public string TagId { get; set; } = string.Empty;
            public string MeasurementName { get; set; } = string.Empty;
            public string TagValue { get; set; } = string.Empty;
            public int QualityMark { get; set; }
            public string StandardValue { get; set; } = string.Empty;
            public string Unit { get; set; } = string.Empty;
        }
    }
}
