using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SystemX.Net.XAdaptor.PC;
using static SystemX.Net.XAdaptor.PC.O2Sensor.NgCode.DBSchemaMap;
using static SystemX.Net.Platform.Common.Util.LogMessage;

namespace SystemX.Net.XAdaptor.PC.O2Sensor.NgCode
{
    public class NGCodeFinder
    {		
		public enum eNGFlag
		{
			NG,
			ERROR
		}

		public enum eNGDataType
		{
			CP,
			LEAK,
			CHECK
		}
		
		public enum eJudgeType
		{
			MIN,
			MAX,
			CHECK
		}

		public string UnsortedNGTitle { get; set; } = "Unknown";
		
		DataTable NGCodeTable { get; set; }

		XAdaptorPC refPCAdaptor;

		public NGCodeFinder(XAdaptorPC refAdaptor)
		{
			refPCAdaptor = refAdaptor;

			NGCodeTable = GetNGCodeTable();
		}
		public void InitialNgCodeTable()
		{
			NGCodeTable = GetNGCodeTable();
		}

		private DataTable GetNGCodeTable()
		{
			DataTable dtResult = null;
			string strQuery = $"SELECT * FROM {DBSchemaMap.TableName_NGCode};";			
			DataSet dtSetResult = refPCAdaptor.WaitSystemQuery(strQuery);

			if(((dtSetResult != null) ? dtSetResult.Tables.Cast<DataTable>().Any(table => table.Rows.Count != 0) : false))
				dtResult = dtSetResult.Tables[0];

			return dtResult;
		}
		public Dictionary<string, string> GetNGCodeDictionary(DataRow dtNGRow)
		{
			Dictionary<string, string> dicNg = new Dictionary<string, string>();

			bool bDisplayMessage = true;
			try
			{
				if (dtNGRow == null)
				{
					dicNg.Add("NTH", "-");

					bDisplayMessage = false;
					throw new Exception("-");
				}

				string strProcNo = dtNGRow[eHistTableCommonCols.ProcNo.ToString()].ToString().Trim();
				string strTestID = dtNGRow[eHistTableCommonCols.TestID.ToString()].ToString().Trim();

				string strResult = "";
				try
				{
					strResult = dtNGRow[eHistTableCommonCols.Result.ToString()].ToString().Trim();
				}
				catch (Exception ex)
				{
					strResult = "0";
				}

				if (strResult == "1" || strResult == "True")
				{
					dicNg.Add("PASS", "-");

					bDisplayMessage = false;
					throw new Exception("-");
				}


				string strUnknwonCode = GetUnknownNGCode(strProcNo, strTestID);

				List<DataRow> vdtNGCodeRow = GetNGCodeList(strProcNo, strTestID);

				if (vdtNGCodeRow == null ? true : vdtNGCodeRow.Count <= 0)
				{
					dicNg.Add(strUnknwonCode, "-");

					bDisplayMessage = false;
					throw new Exception("-");
				}

				string strLogAccessKey = "";

				List<DataRow> vdtDetailRow = null;
				List<DataRow> vdtHISTRow = null;

				//LogAccessKey Exist - PC/DEVICE
				//Not exist - PLC
				try
				{
					strLogAccessKey = dtNGRow[eHistTableCommonCols.LogAccessKey.ToString()]?.ToString().Trim();
					vdtDetailRow = GetNGDetailRow(GetNGDetailData(strProcNo, strLogAccessKey));
				}
				catch (Exception ex)
				{
					throw new Exception(ex.Message);
				}

				DataRow dtNGDetailRow = null;
				DataRow dtNGHISTRow = null;

				DataRow dtNGCodeRow = null;

				if (vdtDetailRow != null && vdtDetailRow.Count > 0)
					dtNGDetailRow = vdtDetailRow[0];

				/*
				if (vdtNGCodeRow[0][eNGCodeTable.CustomCode.ToString()].ToString().Trim() == eNGDataType.CP.ToString())
					dtNGCodeRow = GetNGCodeRowCPLog(vdtNGCodeRow, dtNGDetailRow);
				else if (vdtNGCodeRow[0][eNGCodeTable.CustomCode.ToString()].ToString().Trim() == eNGDataType.LEAK.ToString())
					dtNGCodeRow = GeNGCodeRowLeakLog(vdtNGCodeRow, dtNGRow);
				else
				{
					List<DataRow> vdtFoundRow = vdtNGCodeRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

					if (vdtFoundRow.Count > 0)
						dtNGCodeRow = vdtFoundRow[0];
					else
					{
						dicNg.Add(strUnknwonCode, "-");

						bDisplayMessage = false;
						throw new Exception("-");
					}
				}
				*/

				if (vdtNGCodeRow.Where(x => x[eNGCodeTable.CustomCode.ToString()].ToString().Trim() == eNGDataType.CP.ToString()).ToList().Count > 0)
					dtNGCodeRow = GetNGCodeRowCPLog(vdtNGCodeRow, dtNGDetailRow);
				else if (vdtNGCodeRow.Where(x => x[eNGCodeTable.CustomCode.ToString()].ToString().Trim() == eNGDataType.LEAK.ToString()).ToList().Count > 0)
				{
					vdtHISTRow = GetNGHistRow(GetNGHistData(eHistAllTableList.HIST_Leak, strLogAccessKey));

					if (vdtHISTRow != null && vdtHISTRow.Count > 0)
						dtNGHISTRow = vdtHISTRow[0];

					dtNGCodeRow = GeNGCodeRowLeakLog(vdtNGCodeRow, dtNGHISTRow);
				}
				
				if(dtNGCodeRow == null)
				{
					List<DataRow> vdtFoundRow = vdtNGCodeRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

					if (vdtFoundRow.Count > 0)
						dtNGCodeRow = vdtFoundRow[0];
					else
					{
						dicNg.Add(strUnknwonCode, "-");

						bDisplayMessage = false;
						throw new Exception("-");
					}
				}
				
				if(dtNGCodeRow != null)
					dicNg.Add(dtNGCodeRow[eNGCodeTable.NGCode.ToString()].ToString().Trim(), dtNGCodeRow[eNGCodeTable.Status.ToString()].ToString().Trim());
			}
			catch (Exception ex)
			{
				if (bDisplayMessage)
				{
					MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
					   @"NgCode<Exception> - NGCodeFinder - GetNGCodeDictionary()\r\n" +
					   ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
				}
			}
			finally { }

			return dicNg;
		}
		public string GetNGCode(DataRow dtNGRow)
		{
			if (dtNGRow == null)
				return "NTH";

			string strProcNo = dtNGRow[eHistTableCommonCols.ProcNo.ToString()].ToString().Trim();
			string strTestID = dtNGRow[eHistTableCommonCols.TestID.ToString()].ToString().Trim();

			string strResult = "";

			try
			{
				strResult = dtNGRow[eHistTableCommonCols.Result.ToString()].ToString().Trim();
			}
			catch (Exception ex)
			{
				strResult = "0";
			}

			if (strResult == "1" || strResult == "True")
				return "PASS";

			string strUnknwonCode = GetUnknownNGCode(strProcNo, strTestID);

			List<DataRow> vdtNGCodeRow = GetNGCodeList(strProcNo, strTestID);
			
			if (vdtNGCodeRow == null ? true : vdtNGCodeRow.Count <= 0)
				return strUnknwonCode;

			string strLogAccessKey = "";
			List<DataRow> vdtDetailRow = null;
			List<DataRow> vdtHISTRow = null;

			//LogAccessKey Exist - PC/DEVICE
			//Not exist - PLC
			try
			{
				strLogAccessKey = dtNGRow[eHistTableCommonCols.LogAccessKey.ToString()]?.ToString().Trim();
				vdtDetailRow = GetNGDetailRow(GetNGDetailData(strProcNo, strLogAccessKey));
			}
			catch (Exception ex)
			{
				
            }

			DataRow dtNGDetailRow = null;
			DataRow dtNGHISTRow = null;

			DataRow dtNGCodeRow = null;

			bool bUnknownState = false;

			try
			{
				if (vdtDetailRow != null && vdtDetailRow.Count > 0)
					dtNGDetailRow = vdtDetailRow[0];

				/*
				if (vdtNGCodeRow[0][eNGCodeTable.CustomCode.ToString()].ToString().Trim() == eNGDataType.CP.ToString())
					dtNGCodeRow = GetNGCodeRowCPLog(vdtNGCodeRow, dtNGDetailRow);
				else if (vdtNGCodeRow[0][eNGCodeTable.CustomCode.ToString()].ToString().Trim() == eNGDataType.LEAK.ToString())
					dtNGCodeRow = GeNGCodeRowLeakLog(vdtNGCodeRow, dtNGRow);
				else
				{
					List<DataRow> vdtFoundRow = vdtNGCodeRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

					if (vdtFoundRow.Count > 0)
						dtNGCodeRow = vdtFoundRow[0];
					else
						bUnknownState = true;
				}
				*/

				if (vdtNGCodeRow.Where(x => x[eNGCodeTable.CustomCode.ToString()].ToString().Trim() == eNGDataType.CP.ToString()).ToList().Count > 0)
					dtNGCodeRow = GetNGCodeRowCPLog(vdtNGCodeRow, dtNGDetailRow);
				else if (vdtNGCodeRow.Where(x => x[eNGCodeTable.CustomCode.ToString()].ToString().Trim() == eNGDataType.LEAK.ToString()).ToList().Count > 0)
				{
					vdtHISTRow = GetNGHistRow(GetNGHistData (eHistAllTableList.HIST_Leak, strLogAccessKey));

					if (vdtHISTRow != null && vdtHISTRow.Count > 0)
						dtNGHISTRow = vdtHISTRow[0];

					dtNGCodeRow = GeNGCodeRowLeakLog(vdtNGCodeRow, dtNGHISTRow);
				}
				
				if(dtNGCodeRow == null)
				{
					List<DataRow> vdtFoundRow = vdtNGCodeRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

					if (vdtFoundRow.Count > 0) 
						dtNGCodeRow = vdtFoundRow[0];
					else
						bUnknownState = true;
				}
			}
            catch (Exception ex)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
                   @"NgCode<Exception> - NGCodeFinder - GetNGCode()\r\n" +
                   ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }
            finally { }

			if (bUnknownState)
				return strUnknwonCode;
			else
			{
				if (dtNGCodeRow != null)
					return dtNGCodeRow[eNGCodeTable.NGCode.ToString()].ToString().Trim();
				else
					return strUnknwonCode;

				//return dtNGCodeRow[eNGCodeTable.NGCode.ToString()].ToString().Trim();
			}
		}

		public List<DataRow> GetNGCodeList(string strProcNo, string strTestID)
		{
			List<DataRow> vdtRows = null;

			try
			{
				if (!(NGCodeTable == null))
				{
					/*
					vdtRows = (from dtRow in NGCodeTable.AsEnumerable()
							   where dtRow[eNGCodeTable.ProcNo.ToString()].ToString().Trim() == strProcNo
							   select dtRow).ToList();
					*/

					vdtRows = (from dtRow in NGCodeTable.AsEnumerable()
							   where dtRow[eNGCodeTable.ProcNo.ToString()].ToString().Trim() == strProcNo
							   && dtRow[eNGCodeTable.TestID.ToString()].ToString().Trim() == strTestID
							   select dtRow).ToList();
				}
			}
			catch (Exception ex)
			{
				MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
				   @"NgCode<Exception> - NGCodeFinder - GetNGCodeList()\r\n" +
				   ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
			}
			finally { }

			return vdtRows;
		}

		public DataTable GetNGDetailData(string strProcNum, string strKeyCode)
		{
			DataTable dtResult = null;
			string strQuery = $"SELECT * FROM {TableName_DetailData}" + "_" + strProcNum + " WHERE " +
				$"No IN(SELECT No FROM {TableName_DetailData}" + "_" + strProcNum + " WHERE LogAccessKey = '" + strKeyCode + 
				$"') ORDER BY {eHistDetailTableCols.STEP.ToString()} ASC;";

			DataSet dtSet = refPCAdaptor.WaitSystemQuery(strQuery);

			if (dtSet.Tables.Count > 0)
				dtResult = dtSet.Tables[0];

			return dtResult;
		}

		public List<DataRow> GetNGDetailRow(DataTable dtResult)
		{
			if(dtResult == null)
				return null;

			List<DataRow> vRows = null;

			try
			{
				List<string> vstrNGFlags = Enum.GetNames(typeof(eNGFlag)).ToList();
				vRows = (from unitRow in dtResult.AsEnumerable() where vstrNGFlags.Contains(unitRow[eHistDetailTableCols.CHECK_RETURN.ToString()].ToString().Trim()) select unitRow).ToList();

				vRows = vRows.OrderBy(x => Convert.ToInt32(x[eHistDetailTableCols.STEP.ToString()].ToString().Trim())).Reverse().ToList();
			}
			catch (Exception ex)
			{
				MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
				   @"NgCode<Exception> - NGCodeFinder - GetNGDetailRow()\r\n" +
				   ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
			}
			finally { }

			return vRows;
		}
		public DataTable GetNGHistData(eHistAllTableList setTable, string strKeyCode)
		{
			DataTable dtResult = null;
			string strQuery = $"SELECT * FROM {setTable.ToString()} WHERE " +
				$"No IN(SELECT No FROM {setTable.ToString()} WHERE LogAccessKey = '" + strKeyCode +
				$"') ORDER BY No DESC;";

			DataSet dtSet = refPCAdaptor.WaitSystemQuery(strQuery);

			if (dtSet.Tables.Count > 0)
				dtResult = dtSet.Tables[0];

			return dtResult;
		}

		public List<DataRow> GetNGHistRow(DataTable dtResult)
		{
			if (dtResult == null)
				return null;

			string strNgResult = "0";
			List<DataRow> vRows = null;

			try
			{
				vRows = (from unitRow in dtResult.AsEnumerable() where strNgResult == (unitRow[eHistTableCommonCols.Result.ToString()].ToString().Trim()) select unitRow).ToList();
				vRows = vRows.OrderBy(x => Convert.ToInt32(x[eHistDetailTableCols.STEP.ToString()].ToString().Trim())).Reverse().ToList();
			}
			catch (Exception ex)
			{
				MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
				   @"NgCode<Exception> - NGCodeFinder - GetNGHistRow()\r\n" +
				   ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
			}
			finally { }

			return vRows;
		}

		DataRow GeNGCodeRowLeakLog(List<DataRow> vdtRstRow, DataRow dtDetailNGRow)
		{
			List<DataRow> vFoundRow = null;

			double dMVal = double.NaN;
			double dMin = double.NaN;
			double dMax = double.NaN;
			
			if(dtDetailNGRow == null)
			{
				vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();
				
				if(vFoundRow.Count > 0)
					return vFoundRow[0];
				else
					return null;
			}

			double.TryParse(dtDetailNGRow[eHist_LeakTest.Val_Meas.ToString()].ToString().Trim(), out dMVal);
			double.TryParse(dtDetailNGRow[eHist_LeakTest.Val_Min.ToString()].ToString().Trim(), out dMin);
			double.TryParse(dtDetailNGRow[eHist_LeakTest.Val_Max.ToString()].ToString().Trim(), out dMax);

			if (double.IsNaN(dMVal) ||
			double.IsNaN(dMin) ||
			double.IsNaN(dMax))
			{
				vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();
				
				if(vFoundRow.Count > 0)
					return vFoundRow[0];
			}

			if(dMVal < dMin)
			{
				vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.MIN.ToString()).ToList();
				
				if(vFoundRow.Count > 0)
					return vFoundRow[0];
				else
                {
					vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

					if (vFoundRow.Count > 0)
						return vFoundRow[0];
				}
			}			
			else if(dMVal > dMax)
			{
				vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.MAX.ToString()).ToList();
				
				if(vFoundRow.Count > 0)
					return vFoundRow[0];
				else
                {
					vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

					if (vFoundRow.Count > 0)
						return vFoundRow[0];
				}
			}
			else
            {
				vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

				if (vFoundRow.Count > 0)
					return vFoundRow[0];
			}
			
			return null;
		}
		 
		DataRow GetNGCodeRowCPLog(List<DataRow> vdtRstRow, DataRow dtDetailNGRow)
		{
			List<DataRow> vFoundRow = null;

			double dMVal = double.NaN;
			double dMin = double.NaN;
			double dMax = double.NaN;
			
			if(dtDetailNGRow == null)
			{
				vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();
				
				if(vFoundRow.Count > 0)
					return vFoundRow[0];
				else
					return null;
			}

			double.TryParse(dtDetailNGRow[eHistDetailTableCols.MEASURE_VALUE.ToString()].ToString().Trim(), out dMVal);
			double.TryParse(dtDetailNGRow[eHistDetailTableCols.MIN_VALUE.ToString()].ToString().Trim(), out dMin);
			double.TryParse(dtDetailNGRow[eHistDetailTableCols.MAX_VALUE.ToString()].ToString().Trim(), out dMax);

			int iGetStep = 0;
			int.TryParse(dtDetailNGRow[eHistDetailTableCols.STEP.ToString()].ToString().Trim(), out iGetStep);

			if (double.IsNaN(dMVal) ||
			double.IsNaN(dMin) ||
			double.IsNaN(dMax))
			{
				vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();
				
				if(vFoundRow.Count > 0)
					return vFoundRow[0];
			}
			else if(dMVal < dMin)
			{
				vFoundRow = vdtRstRow.Where(x => (x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.MIN.ToString()) &&
				(x[eNGCodeTable.StepNo.ToString()].ToString().Trim() == iGetStep.ToString())).ToList();
				
				if(vFoundRow.Count > 0)
					return vFoundRow[0];
				else
				{
					vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

					if (vFoundRow.Count > 0)
						return vFoundRow[0];
				}
			}			
			else if(dMVal > dMax)
			{
				vFoundRow = vdtRstRow.Where(x => (x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.MAX.ToString()) &&
				(x[eNGCodeTable.StepNo.ToString()].ToString().Trim() == iGetStep.ToString())).ToList();

				if (vFoundRow.Count > 0)
					return vFoundRow[0];
				else
                {
					vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

					if (vFoundRow.Count > 0)
						return vFoundRow[0];
				}
			}
			else 
			{
				vFoundRow = vdtRstRow.Where(x => x[eNGCodeTable.Type.ToString()].ToString().Trim() == eJudgeType.CHECK.ToString()).ToList();

				if (vFoundRow.Count > 0)
					return vFoundRow[0];
			}

			return null;		
		}

		string GetUnknownNGCode(string strProcNo, string strTestID)
		{
			string strNGCodeResult = UnsortedNGTitle + ":" + strProcNo + "-" + strTestID;

			return strNGCodeResult;
		}
		
		public eReworkType GetReworkType(string strNGCode)
		{
			List<DataRow> vdtRstRow = (from dtNGRow in NGCodeTable.AsEnumerable() where dtNGRow[eNGCodeTable.NGCode.ToString()].ToString().Trim() == strNGCode select dtNGRow).ToList();
			eReworkType R_Type = eReworkType.Unknown;

			if(vdtRstRow.Count == 0)
				return R_Type;

			string strRType = "";

			try
			{
				strRType = vdtRstRow[0][eNGCodeTable.ReworkType.ToString()].ToString().Trim();
			}
			catch (Exception ex)
			{
				MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") +
				   @"NgCode<Exception> - NGCodeFinder - GetReworkType()\r\n" +
				   ex.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
			}
			finally { }

			if (!Enum.TryParse(strRType, out R_Type))
				return R_Type;

			return R_Type;
		}
    }
}
