using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SystemX.Product.ALIS.Interface;
using SystemX.Product.CP.TRA;
using SystemX.Product.TRA.UIControl;

using static SystemX.Product.TRA.DataManager.DMOverview;
using static SystemX.Product.CP.TRA.Commons;

namespace SystemX.Product.TRA.DataManager
{
    public class DMTestSummary
    {
        public enum eColHideListLog
        {
            No,
            AccessKey,
            //TestID
        }

        public enum eColTestLog
        {
            No,
            AccessKey,
            //TestID,
            StepID,
            MeasVal,
            MeasValStr,
            Message,
            GlobalMin,
            GlobalMax,
            Result
            //Duration
        }

        public enum eColHideListTL
        {
            No,
            TestlistNo,
            StepVersion,
            Enable,
            IsGlobal,
            UpdateDT
        }

        public enum eColTestlist
        {
            No,
            TestlistNo,
            StepID,
            Variant,
            Gate,
            Activate,
            StepVersion,
            Enable,
            Position,
            StepDesc,
            UseFunction,
            SpecMin,
            SpecMax,
            Dim,
            IsGlobal,
            UpdateDT
        }

        public enum eColTestSummary
        {
            StepID,
            Average,
            Total,
            OK,
            NG //NOK
        }

        public SqlConnection DBConn { get; private set; }
        public SqlConnection ShortTermDBConn { get; private set; }
        public SqlConnection LongTermDBConn { get; private set; }

        private SqlCommand SQLCmd { get; set; }

        public DataTable dtHistVersionTL;

        public int nCurrentTLMaxStepVersion { get; set; }

        //public DataTable this[int i] => dtEachVersionTL[i];

        public DMTestSummary(eSelectDataView SelectView, IDataBaseController getDBController)
        {
            DBConn = getDBController.GetMainConn();

            if (SelectView == eSelectDataView.DataDocumentViewC1)
            {
                ShortTermDBConn = getDBController.GetShortTermConn1();

                LongTermDBConn = getDBController.GetLongTermConn1();
            }
            else if (SelectView == eSelectDataView.DataDocumentViewC2)
            {
                ShortTermDBConn = getDBController.GetShortTermConn2();

                LongTermDBConn = getDBController.GetLongTermConn2();
            }
        }

        public DataTable SearchTestlist(SelectedDataCollection data, int nHistChkStepVer = int.MinValue, bool bOnlyNewStepVersion = true)
        {
            DataTable dtResult = new DataTable();
            DataTable dtResultChk = new DataTable();

            string strQuery = string.Empty;

            if (data == null)
                return dtResult;

            strQuery = $"SELECT A.ProdNo_C, B.ProdNo_P, B.UpdateDT, D.TestCode, D.Gate1, D.Gate2, E.FileName, A.RegUserComment, B.Description, C.GroupName, C.ModelName, A.VariantNo AS 'TestListNo', A.Config, E.TestType, E.Version, E.ProdCode, B.UseTLPosition, B.TestListFileNo, E.UpdateDT AS 'TestListFileUpdateDT', A.VariantNo FROM [PROD_Release] AS A WITH(NOLOCK) " +
               $"INNER JOIN(SELECT * FROM [PROD_Variant] WITH(NOLOCK)) AS B ON A.VariantNo = B.No " +
               $"INNER JOIN(SELECT * FROM [PROD_Group] WITH(NOLOCK)) AS C ON B.GroupNo = C.No " +
               $"INNER JOIN(SELECT * FROM [STAT_TestCode] WITH(NOLOCK)) AS D ON A.TestCodeNo = D.No " +
               $"INNER JOIN(SELECT * FROM [STOR_TestListFile] WITH(NOLOCK)) AS E ON B.TestListFileNo = E.No " +
               $"WHERE A.ProdNo_C = '{data.ProductNo}' AND D.TestCode = '{data.TestCode}' AND E.TestType = '{data.TestType}' AND E.Version = '{data.FileVersion}' AND E.ProdCode = '{data.ProductionCode}';";

            SQLCmd = new SqlCommand(strQuery, DBConn);
            SQLCmd.CommandTimeout = DMCommon.nDefaultScanTime;

            DbDataReader dtCompReader = SQLCmd.ExecuteReader();
            DataTable dtCompResult = new DataTable();

            dtCompResult.Load(dtCompReader);

            if (Commons.isHasRow(dtCompResult) == false)
                return dtResult;

            string strCompVariNo = dtCompResult.Rows[0]["VariantNo"].ToString();
            string strCompFileNo = dtCompResult.Rows[0]["TestListFileNo"].ToString();

            dtCompReader.Close();

            string strGetTestListFileNo = string.Empty;

            if (strCompVariNo.CompareTo(data.TestListVariantNo) == 0 &&
            strCompFileNo.CompareTo(data.TestListFileNo) == 0)
                strGetTestListFileNo = data.TestListFileNo;
            else
                strGetTestListFileNo = strCompFileNo;

            strQuery = $"SELECT LatestStepVersion FROM [HIST_TestListFileLatestStepVersion] WITH(NOLOCK) WHERE TestListFileNo = {strGetTestListFileNo};";

            SQLCmd = new SqlCommand(strQuery, DBConn);
            SQLCmd.CommandTimeout = DMCommon.nDefaultScanTime;

            DbDataReader dtReaderChk = SQLCmd.ExecuteReader();

            dtResultChk.Clear();
            dtResultChk.Load(dtReaderChk);

            int nMaxStepVersion = Convert.ToInt32(dtResultChk.Rows[0]["LatestStepVersion"].ToString());

            nCurrentTLMaxStepVersion = nMaxStepVersion;

            dtReaderChk.Close();

            //항상 최신 스텝 버전을 체크
            strQuery = $"SELECT * FROM ( " +
                $"SELECT *, ROW_NUMBER() OVER(PARTITION BY StepID ORDER BY StepVersion DESC) " +
                $"AS RN FROM VRFY_TestListFileRelease WITH (NOLOCK, INDEX=[CSK_VRFY_Release_2]) WHERE TestListFileNo = {strGetTestListFileNo}) AS X " +
                $"WHERE X.RN = 1 ORDER BY X.StepID ASC;";

            SQLCmd = new SqlCommand(strQuery, DBConn);
            SQLCmd.CommandTimeout = DMCommon.nDefaultScanTime;

            DbDataReader dtReader = SQLCmd.ExecuteReader();

            dtResult.Clear();
            dtResult.Load(dtReader);

            dtReader.Close();

            if (bOnlyNewStepVersion)
            {
                dtHistVersionTL = null;
            }
            else
            {
                //Hist 목록 검색 스텝 버전 리스트만 검색하여 사용
                dtHistVersionTL = new DataTable();

                strQuery = $"SELECT * FROM ( " +
                    $"SELECT *, ROW_NUMBER() OVER(PARTITION BY StepID ORDER BY StepVersion DESC) " +
                    $"AS RN FROM VRFY_TestListFileRelease WITH (NOLOCK, INDEX=[CSK_VRFY_Release_2]) WHERE TestListFileNo = {strGetTestListFileNo} AND StepVersion <= {nHistChkStepVer}) AS X " +
                    $"WHERE X.RN = 1 ORDER BY X.StepID ASC, StepVersion DESC;";

                SQLCmd = new SqlCommand(strQuery, DBConn);
                SQLCmd.CommandTimeout = DMCommon.nDefaultScanTime;

                DbDataReader dtHistReader = SQLCmd.ExecuteReader();

                dtHistVersionTL.Clear();
                dtHistVersionTL.Load(dtHistReader);

                dtHistReader.Close();

                //PK 키 지정 >
                //TODO : Primary Key Access Error > 업데이트 된 동일 스텝이 존재시 PK 지정 실패
                DataColumn[] keysHistStepVer = new DataColumn[1];
                keysHistStepVer[0] = new DataColumn();
                keysHistStepVer[0] = dtHistVersionTL.Columns["StepID"];

                dtHistVersionTL.PrimaryKey = keysHistStepVer;

                /*
                dtEachVersionTL = new DataTable[nMaxStepVersion + 1];

                int nStartStepVer = nMaxStepVersion - 5;

                if (nStartStepVer < 0)
                    nStartStepVer = 0;

                for (int i = nStartStepVer; i <= nMaxStepVersion; i++)
                {
                    dtEachVersionTL[i] = new DataTable();

                    strQuery = $"SELECT * FROM ( " +
                    $"SELECT *, ROW_NUMBER() OVER(PARTITION BY StepID ORDER BY StepVersion DESC) " +
                    $"AS RN FROM VRFY_TestListFileRelease WITH (NOLOCK, INDEX=[CSK_VRFY_Release_2]) WHERE TestListFileNo = {strGetTestListFileNo} AND StepVersion <= {i}) AS X " +
                    $"WHERE X.RN = 1 ORDER BY X.StepID ASC, StepVersion DESC;";

                    SQLCmd = new SqlCommand(strQuery, DBConn);
                    SQLCmd.CommandTimeout = DMCommon.nDefaultScanTime;

                    DbDataReader dtReader = SQLCmd.ExecuteReader();

                    dtEachVersionTL[i].Clear();
                    dtEachVersionTL[i].Load(dtReader);

                    dtReader.Close();

                    //PK 키 지정 >
                    //TODO : Primary Key Access Error > 업데이트 된 동일 스텝이 존재시 PK 지정 실패
                    DataColumn[] keysEachStepVer = new DataColumn[1];
                    keysEachStepVer[0] = new DataColumn();
                    keysEachStepVer[0] = dtEachVersionTL[i].Columns["StepID"];

                    dtEachVersionTL[i].PrimaryKey = keysEachStepVer;
                }
                */
            }

            //PK 키 지정
            DataColumn[] keys1 = new DataColumn[1];
            keys1[0] = new DataColumn();
            keys1[0] = dtResult.Columns["StepID"];

            dtResult.PrimaryKey = keys1;

            return dtResult;
        }

        public DataTable RefineStepVersion(DataTable dtTestlist, SelectedDataCollection data)
        {
            var DuplicatedSteps = dtTestlist.AsEnumerable().GroupBy(x => x[eColTestlist.StepID.ToString()]).
                Select(x => new { StepID = x.Key, Count = x.Count() }).Where(x => x.Count > 1);
            
            foreach(var value in DuplicatedSteps)
            {
                List<DataRow> vdtRow = dtTestlist.AsEnumerable().Where(x => x[eColTestlist.StepID.ToString()].ToString() == value.StepID.ToString()).ToList();
                DataRow vExcRow = vdtRow.Where(x => x[eColTestlist.StepVersion.ToString()].ToString() == data.StepVersion).FirstOrDefault();

                if(vExcRow == null)
                {
                    int nMaxVer = vdtRow.Max(x => Convert.ToInt32(x[eColTestlist.StepVersion.ToString()]));

                    vExcRow = vdtRow.Where(x => Convert.ToInt32(x[eColTestlist.StepVersion.ToString()]) == nMaxVer).FirstOrDefault();
                }

                vdtRow.Remove(vExcRow);

                foreach (DataRow dtRow in vdtRow)
                    dtTestlist.Rows.Remove(dtRow);
            }

            return dtTestlist;
        }

        public DataTable SearchTestSummary(DateTime dtTestTime, List<Tuple<ulong, ulong>> vnpAccKeys, List<Int64> vnpSummaryNo)
        {
            DataTable dtResult = new DataTable();
            string strQuery = string.Empty;
            string strLongTerm = "HIST_TestResult";
            string strShortTerm = "HIST_TestResult";

            DateTime dtNow = DateTime.Now;

            int nDiffMonth = 12 * (dtNow.Year - dtTestTime.Year) + (dtNow.Month - dtTestTime.Month);

            string strTableTerm = nDiffMonth > 3 ? strLongTerm : strShortTerm;
            bool bLongTermTableUse = nDiffMonth > 3 ? true : false;

            if (vnpAccKeys == null || vnpAccKeys.Count <= 0)
                return dtResult;

            /*
            strQuery += $"SELECT ";
            strQuery += $"StepID, ";
            strQuery += $"AVG(CASE WHEN (X.[MeasValStr] = null OR X.[MeasValStr] = '') AND (X.[Message] = null OR X.[Message] = '') AND (X.[MeasVal] != 0.00000 AND X.[Result] != 'NONE') THEN X.[MeasVal] ELSE null END) AS Average, ";
            strQuery += $"COUNT(X.[Result]) AS Total, ";
            strQuery += $"COUNT(CASE WHEN X.[Result] = 'OK' THEN 1 END) AS OK, ";
            strQuery += $"COUNT(CASE WHEN X.[Result] = 'NG' OR X.[Result] = 'ERROR' THEN 1 END) AS NG "; 
            strQuery += " ";
            strQuery += $"FROM [{strTableTerm}] AS X ";
            strQuery += $"WITH(NOLOCK) INNER JOIN [{DMCommon.SummaryLogTable}] AS Y ON ";

            int nIdx = 0;

            strQuery += $"(";

            foreach (Int64 npKey in vnpSummaryNo)
            {
                strQuery += $"Y.[NO] = {npKey} ";

                if (vnpAccKeys.Count - 1 > nIdx)
                    strQuery += " OR ";

                nIdx++;
            }

            strQuery += $") ";
            strQuery += $"WHERE ";

            nIdx = 0;

            foreach(Tuple<ulong, ulong> npKey in vnpAccKeys)
            {
                strQuery += $"(X.[AccessKey] <= {npKey.Item2} AND X.[AccessKey] >= {npKey.Item1})";

                if (vnpAccKeys.Count - 1 > nIdx)
                    strQuery += " OR ";

                nIdx++;
            }
                
            strQuery += " ";
            strQuery += $"GROUP BY ";
            strQuery += $"X.[StepID]";
            strQuery += " ";
            strQuery += $"ORDER BY ";
            strQuery += $"X.[StepID]";
            strQuery += ";";
            */
            /*
            SELECT 
            Y.StepID, 
            CASE X.StepVersion WHEN 0 THEN 'O' ELSE 'X' END AS SV0,
            CASE X.StepVersion WHEN 1 THEN 'O' ELSE 'X' END AS SV1,
            CASE X.StepVersion WHEN 2 THEN 'O' ELSE 'X' END AS SV2,
            CASE X.StepVersion WHEN 3 THEN 'O' ELSE 'X' END AS SV3,
            CASE X.StepVersion WHEN 4 THEN 'O' ELSE 'X' END AS SV4,
            CASE X.StepVersion WHEN 5 THEN 'O' ELSE 'X' END AS SV5,
            AVG(CASE WHEN (Y.[MeasValStr] = null OR Y.[MeasValStr] = '') AND 
            (Y.[Message] = null OR Y.[Message] = '') AND
            (Y.[MeasVal] != 0.00000 AND Y.[Result] != 'NONE') THEN Y.[MeasVal] ELSE null END) AS Average, 
            COUNT(Y.[Result]) AS Total, COUNT(CASE WHEN Y.[Result] = 'OK' THEN 1 END) AS OK, 
            COUNT(CASE WHEN Y.[Result] = 'NG' OR Y.[Result] = 'ERROR' THEN 1 END) AS NG  
            FROM [{DMCommon.SummaryLogTable}] AS X WITH(NOLOCK) 
            INNER JOIN [HIST_TestResultLongTerm] AS Y WITH(NOLOCK) ON (Y.AccessKey <= X.AccessEnd AND Y.AccessKey >= X.AccessStart)
            WHERE (X.[No] = 120202 OR X.[NO] = 120204 OR X.[NO] = 120206 OR X.[NO] = 120208 OR X.[NO] = 120211 OR X.[NO] = 120212 OR X.[NO] = 120214  OR X.[NO] = 120216  OR X.[NO] = 120218  OR X.[NO] = 120220  OR X.[NO] = 120222)
            GROUP BY Y.[StepID], X.[StepVersion] ORDER BY Y.[StepID];
            */

            strQuery += $"SELECT ";
            strQuery += $"Y.[StepID], ";

            //for (int i = 0; i <= nCurrentTLMaxStepVersion; i++)
            //    strQuery += $"CASE X.StepVersion WHEN " + i.ToString() + " THEN 'O' ELSE 'X' END AS SV" + i.ToString() + ", ";

            strQuery += $"AVG(CASE WHEN (Y.[MeasValStr] = NULL OR Y.[MeasValStr] = '') AND (Y.[Message] = NULL OR Y.[Message] = '') AND (Y.[MeasVal] != 0.00000 AND Y.[Result] != 'NONE') THEN Y.[MeasVal] ELSE NULL END) AS Average, ";
            strQuery += $"COUNT(Y.[Result]) AS Total, ";
            strQuery += $"COUNT(CASE WHEN Y.[Result] = 'OK' THEN 1 END) AS OK, ";
            strQuery += $"COUNT(CASE WHEN Y.[Result] = 'NG' OR X.[Result] = 'ERROR' THEN 1 END) AS NG ";
            strQuery += $" ";
            strQuery += $"FROM [{DMCommon.SummaryLogTable}] AS X WITH(NOLOCK) ";
            strQuery += $"INNER JOIN [{strTableTerm}] AS Y WITH(NOLOCK) ON (Y.AccessKey BETWEEN X.AccessStart AND X.AccessEnd) ";

            int nIdx = 0;

            /*
            strQuery += $"WHERE (";

            foreach (Int64 npKey in vnpSummaryNo)
            {
                strQuery += $"X.[No] = {npKey} ";

                if (vnpAccKeys.Count - 1 > nIdx)
                    strQuery += " OR ";

                nIdx++;
            }

            strQuery += $") ";
            */

            strQuery += $"WHERE X.[No] IN (";

            foreach (Int64 npKey in vnpSummaryNo)
            {
                strQuery += $"{npKey}";

                if (vnpSummaryNo.Count - 1 > nIdx)
                    strQuery += ", ";

                nIdx++;
            }

            strQuery += $") ";


            strQuery += $"GROUP BY Y.[StepID], X.[StepVersion] ORDER BY Y.[StepID];";

            if (bLongTermTableUse) SQLCmd = new SqlCommand(strQuery, LongTermDBConn);
            else SQLCmd = new SqlCommand(strQuery, ShortTermDBConn);
            SQLCmd.CommandTimeout = DMCommon.nDefaultScanTime;

            DbDataReader dtReader = SQLCmd.ExecuteReader();

            dtResult.Load(dtReader);

            dtReader.Close();

            return dtResult;
        }

        DataTable GetRawResult(DetailTestDataCollection data)
        {
            DataTable dtResult = new DataTable();
            string strQuery = string.Empty;

            if (data == null)
                return dtResult;
                        

            SQLCmd = new SqlCommand(strQuery, ShortTermDBConn);
            SQLCmd.CommandTimeout = DMCommon.nDefaultScanTime;

            DbDataReader dtReader = SQLCmd.ExecuteReader();

            dtResult.Load(dtReader);

            dtReader.Close();

            return dtResult;
        }
    }
}
