using ClosedXML.Excel;
using LHDN.CRM.Models.ViewModels;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static LHDN.CRM.BC.Common.Constant;

namespace LHDN.CRM.BC.Common
{
    public class Utilities
    {
        public static string GetUserCacheName(string strLoginID)
        {
            return Constant.Sessions.LoginInfo + "_" + strLoginID.ToLower();
        }

        public static bool CompareByteArray(byte[] obj1, byte[] obj2)
        {
            bool blnSame = false;
            if (obj1 != null && obj2 != null)
            {
                blnSame = Convert.ToBase64String(obj1) == Convert.ToBase64String(obj2);
            }
            return blnSame;
        }

        public static object GetPropertyValue(object obj, string propertyName)
        {
            return obj.GetType().GetProperty(propertyName) == null ? "" : obj.GetType().GetProperty(propertyName).GetValue(obj, null);
        }

        public static bool CompareDateTime(object obj1, object obj2)
        {
            bool blnResult;
            if (obj1 is DateTime && obj2 is DateTime)
            {
                if (Convert.ToDateTime(obj1).ToString("yyyyMMddHHmmss") != Convert.ToDateTime(obj2).ToString("yyyyMMddHHmmss"))
                {
                    blnResult = false;
                }
                else
                {
                    blnResult = true;
                }
            }
            else
            {
                blnResult = false;
            }
            return blnResult;
        }

        public static bool IsList(object o)
        {
            if (o == null) return false;
            return o is IList &&
                   o.GetType().IsGenericType &&
                   o.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>));
        }

        public static AuditDetailViewModel GetAuditDetail(string fieldName, string oldValue, string newValue)
        {
            AuditDetailViewModel obj = new AuditDetailViewModel();

            obj.FieldName = fieldName;
            if (string.IsNullOrEmpty(oldValue))
            {
                obj.OldValue = string.Empty;
            }
            else
            {
                obj.OldValue = oldValue;
            }

            if (string.IsNullOrEmpty(newValue))
            {
                obj.NewValue = string.Empty;
            }
            else
            {
                obj.NewValue = newValue;
            }

            return obj;
        }

        public static List<DropdownDetailViewModel> SortDDL(List<DropdownDetailViewModel> ddl)
        {
            if (ddl.FirstOrDefault()?.SeqNo > 0)
                return ddl.OrderBy(x => x.SeqNo).ToList();
            else
                return ddl.OrderBy(x => x.Text).ToList();
        }
        public static string GetUserShortname(string strUserName)
        {
            List<string> lstUserName = strUserName.Split(" ").ToList();
            string strShortName = "";
            if (lstUserName != null)
            {
                if (lstUserName.Count > 1)
                {
                    strShortName = lstUserName[0][0].ToString() + lstUserName[1][0].ToString();
                }
                else
                {
                    strShortName = lstUserName[0][0].ToString() + lstUserName[0][1].ToString();
                }
            }
            return strShortName;
        }

        public static List<AdvanceRulesViewModel> GenerateRowIDForAdvanceRules(List<AdvanceRulesViewModel> lstObj, bool isBasicMode = false)
        {
            List<AdvanceRulesViewModel> lstRules = new List<AdvanceRulesViewModel>();
            if (lstObj != null)
            {
                int intCount = 1;
                foreach (AdvanceRulesViewModel rulesItem in lstObj)
                {
                    bool blnSkipRule = false;
                    rulesItem.ViewRuleID = (rulesItem.IsFromDB) ? rulesItem.ViewRuleID : rulesItem.Sequence * -1;

                    foreach (RuleGroupViewModel ruleGroupItem in rulesItem.RuleGroup)
                    {
                        ruleGroupItem.ViewRuleID = rulesItem.ViewRuleID;
                        ruleGroupItem.ViewRuleGroupID = ruleGroupItem.IsFromDB ? ruleGroupItem.ViewRuleGroupID : intCount * -1;
                        intCount++;
                        int intFieldCount = intCount;
                        ruleGroupItem.FieldValues.ForEach(c =>
                        {// Assign ID for new row
                            if (!c.IsFromDB)
                            {
                                c.ViewRuleGroupFieldsID = intFieldCount * -1;
                                c.ViewRuleGroupID = ruleGroupItem.ViewRuleGroupID;
                                c.FieldValue = GetFieldValue(ruleGroupItem.FieldType, c.FieldValue);
                                intFieldCount++;
                            }
                            if (isBasicMode && c.IsFromDB)
                                blnSkipRule = true;
                        });
                    }
                    if (!blnSkipRule)
                        lstRules.Add(rulesItem);
                }

                lstObj = lstRules;
            }

            return lstObj;
        }

        public static dynamic GetFieldValue(int fieldType, dynamic value)
        {
            if (fieldType == 14)
            {
                DateTime dt;
                // return Convert.ToDateTime(value, CultureInfo.InvariantCulture);
                if (DateTime.TryParseExact(value, "dd/MM/yyyy hh:mm a", null,DateTimeStyles.None, out dt))
                    return DateTime.ParseExact(value, "dd/MM/yyyy hh:mm a", null);
                else
                     return Convert.ToDateTime(value, CultureInfo.InvariantCulture);

                    //return  DateTime.ParseExact(value, "dd/MM/yyyy hh:mm a", CultureInfo.InvariantCulture);
            }
            else
                return value;
        }

        public static DataSet GenerateAdvanceRulesViewTables(List<AdvanceRulesViewModel> lstObj)
        {
            DataSet ds = new DataSet();
            DataTable dTblRules = CreateAdvanceRulesTable();
            DataTable dTblRuleGroup = CreateAdvanceRulesGroupTable();
            DataTable dTblRuleFieldValue = CreateAdvanceRulesFieldValueTable();
            ds.Tables.Add(dTblRules);
            ds.Tables.Add(dTblRuleGroup);
            ds.Tables.Add(dTblRuleFieldValue);
            if (lstObj != null)
            {
                foreach (AdvanceRulesViewModel rulesItem in lstObj)
                {
                    dTblRules.Rows.Add(rulesItem.ViewRuleID, rulesItem.Sequence, rulesItem.RuleType, rulesItem.RuleOperator, rulesItem.GroupingOperator, rulesItem.IsFromDB);

                    foreach (RuleGroupViewModel ruleGroupItem in rulesItem.RuleGroup)
                    {
                        dTblRuleGroup.Rows.Add(ruleGroupItem.ViewRuleGroupID, ruleGroupItem.ViewRuleID, ruleGroupItem.DisplayField,
                            ruleGroupItem.FieldType, ruleGroupItem.FieldMapping, ruleGroupItem.FieldOperator, rulesItem.IsFromDB);
                        foreach (FieldValueViewModel fieldItem in ruleGroupItem.FieldValues)
                        {
                            if (ruleGroupItem.FieldType == AdvancedRules.FieldType.DateType)
                            {
                                fieldItem.FieldValue = Convert.ToDateTime(fieldItem.FieldValue, CultureInfo.InvariantCulture);
                                // fieldItem.FieldValue = ((DateTime)fieldItem.FieldValue).ToLocalTime();
                            }
                            dTblRuleFieldValue.Rows.Add(fieldItem.ViewRuleGroupFieldsID, fieldItem.ViewRuleGroupID, fieldItem.FieldValue, fieldItem.IsFromDB);
                        }
                    }

                }
            }

            return ds;
        }

        public static DataTable CreateAdvanceRulesTable()
        {
            DataTable dTblRules = new DataTable();

            dTblRules.Columns.Add("ViewRuleID", typeof(int));
            dTblRules.Columns.Add("Sequence", typeof(int));
            dTblRules.Columns.Add("RuleType", typeof(string));
            dTblRules.Columns.Add("RuleOperator", typeof(string));
            dTblRules.Columns.Add("GroupingOperator", typeof(string));
            dTblRules.Columns.Add("IsFromDB", typeof(bool));

            return dTblRules;
        }

        public static DataTable CreateAdvanceRulesGroupTable()
        {
            DataTable dTblRuleGroup = new DataTable();

            dTblRuleGroup.Columns.Add("ViewRuleGroupID", typeof(int));
            dTblRuleGroup.Columns.Add("ViewRuleID", typeof(int));
            dTblRuleGroup.Columns.Add("DisplayField", typeof(string));
            dTblRuleGroup.Columns.Add("FieldType", typeof(string));
            dTblRuleGroup.Columns.Add("FieldMapping", typeof(string));
            dTblRuleGroup.Columns.Add("FieldOperator", typeof(int));
            dTblRuleGroup.Columns.Add("IsFromDB", typeof(bool));

            return dTblRuleGroup;
        }

        public static DataTable CreateAdvanceRulesFieldValueTable()
        {
            DataTable dTblRules = new DataTable();

            dTblRules.Columns.Add("ViewRuleGroupFieldsID", typeof(long));
            dTblRules.Columns.Add("ViewRuleGroupID", typeof(int));
            dTblRules.Columns.Add("FieldValue");
            dTblRules.Columns.Add("IsFromDB", typeof(bool));

            return dTblRules;
        }
        public static IList<TResult> DataTableToList<TResult>(DataTable table) where TResult : class, new()
        {
            IList<PropertyInfo> properties = typeof(TResult).GetProperties().ToList();
            IList<TResult> result = new List<TResult>();

            foreach (var row in table.Rows)
            {
                var item = CreateItemFromRow<TResult>((DataRow)row, properties);
                result.Add(item);
            }

            return result;
        }

        private static TResult CreateItemFromRow<TResult>(DataRow row, IList<PropertyInfo> properties) where TResult : class, new()
        {
            TResult item = new TResult();

            foreach (var p in properties)
            {
                if (row.Table.Columns.Contains(p.Name))
                {
                    if (string.Equals(row[p.Name].GetType().Name, DBNull.Value))
                    {
                        if (Nullable.GetUnderlyingType(p.PropertyType) != null)
                            p.SetValue(item, row[p.Name], null);
                    }
                    else if (p.PropertyType.IsGenericType &&
                        p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) // Check if DTO defined property is Nullable
                    {
                        if (Nullable.GetUnderlyingType(p.PropertyType) == row[p.Name].GetType())
                            p.SetValue(item, row[p.Name], null);
                    }
                    else if (p.PropertyType == typeof(string))
                        p.SetValue(item, row[p.Name].ToString(), null);
                    else if (p.PropertyType == row[p.Name].GetType())
                        p.SetValue(item, row[p.Name], null);
                }
            }
            return item;
        }

        public static AdvancedRulesMainViewModel RetrieveAdvanceRulesViewModel(DataSet ds)
        {
            AdvancedRulesMainViewModel vmAdvRule = new AdvancedRulesMainViewModel();
            if (ds.Tables[0] != null && ds.Tables[0].Rows.Count > 0)
            {
                vmAdvRule = DataTableToList<AdvancedRulesMainViewModel>(ds.Tables[0]).FirstOrDefault();
            }
            if (ds.Tables[1] != null && ds.Tables[1].Rows.Count > 0)
            {
                vmAdvRule.Rules = DataTableToList<AdvanceRulesViewModel>(ds.Tables[1]).ToList();
                if (ds.Tables[2] != null && ds.Tables[2].Rows.Count > 0)
                {

                    List<AdvanceRulesViewModel> lstRules = new List<AdvanceRulesViewModel>();
                    foreach (AdvanceRulesViewModel rules in vmAdvRule.Rules)
                    {
                        using (DataView dv = new DataView(ds.Tables[2].Copy()))
                        {
                            //Populate Rule Groups
                            string strFilter = "ViewRuleID = ";
                            dv.RowFilter = strFilter + rules.ViewRuleID.ToString();
                            if (dv.Count > 0)
                            {
                                rules.RuleGroup = DataTableToList<RuleGroupViewModel>(dv.ToTable()).ToList();
                                List<RuleGroupViewModel> lstRuleGroup = new List<RuleGroupViewModel>();
                                //Populate Field values
                                foreach (RuleGroupViewModel rulesGroup in rules.RuleGroup)
                                {
                                    using (DataView dvField = new DataView(ds.Tables[3].Copy()))
                                    {
                                        string strFilterField = "ViewRuleGroupID = ";
                                        dvField.RowFilter = strFilterField + rulesGroup.ViewRuleGroupID.ToString();
                                        if (dvField.Count > 0)
                                        {
                                            List<FieldValueViewModel> lstFieldValues = new List<FieldValueViewModel>();
                                            foreach (DataRow dr in dvField.ToTable().Rows)
                                            {
                                                FieldValueViewModel objFieldValue = new FieldValueViewModel();
                                                objFieldValue.ViewRuleGroupFieldsID = Convert.ToInt64(dr["ViewRuleGroupFieldsID"].ToString());
                                                objFieldValue.ViewRuleGroupID = Convert.ToInt32(dr["ViewRuleGroupID"].ToString());
                                                if (rulesGroup.FieldType == 15 || rulesGroup.FieldType == 50 || rulesGroup.FieldType == 51)
                                                {
                                                    objFieldValue.FieldValue = Convert.ToInt64(dr["FieldValue"].ToString());
                                                }
                                                else
                                                {
                                                    objFieldValue.FieldValue = dr["FieldValue"].ToString();
                                                }
                                                objFieldValue.IsFromDB = Convert.ToBoolean(dr["IsFromDB"]);
                                                objFieldValue.IsMultiple = false;
                                                lstFieldValues.Add(objFieldValue);
                                            }
                                            rulesGroup.FieldValues = lstFieldValues;
                                            //rulesGroup.FieldValues = DataTableToList<FieldValueViewModel>(dvField.ToTable()).ToList();
                                        }
                                    }
                                    lstRuleGroup.Add(rulesGroup);
                                }
                                rules.RuleGroup = lstRuleGroup;
                                lstRules.Add(rules);
                            }
                        }
                    }
                    vmAdvRule.Rules = lstRules;
                }

                if (ds.Tables.Count > 4) //todo
                {
                    if (ds.Tables[4] != null && ds.Tables[4].Rows.Count > 0)
                    {
                        vmAdvRule.PermissionUsers = DataTableToList<PermissionUserViewModel>(ds.Tables[4]).ToList();
                    }

                    if (ds.Tables[5] != null && ds.Tables[5].Rows.Count > 0)
                    {
                        vmAdvRule.PermissionRoles = DataTableToList<PermissionRoleViewModel>(ds.Tables[5]).ToList();
                    }
                }
            }

            return vmAdvRule;
        }

        public static string GetAppSetting(string strKey)
        {
            return ConfigurationManager.AppSettings[strKey];
        }

        public static string GetConnSetting(string strKey)
        {
            ConnectionStringSettings connString = ConfigurationManager.ConnectionStrings[strKey];
            return connString != null ? connString.ConnectionString : string.Empty;
        }

        public static string GetAppPath()
        {
            return Directory.GetCurrentDirectory();
        }

        public static bool VerifyUserAccessToViewTP(Constant.TableType enumPageType, UserInfoViewModel userInfo,
                                                    List<BranchListViewModel> lstBranch,
                                                    string strVIPCode, int intCWPenaksiranCPID,
                                                    int intCWPenaksiranCKHTID, int intCWPungutanCPID,
                                                    int intCWPungutanCKHTID,
                                                    int intCWGuamanSivilID)
        {
            bool blnIsValid = false;

            switch (enumPageType)
            {
                case Constant.TableType.TaxPayer:
                    if (strVIPCode == "1") // Is VIP
                    {
                        // Check if User is able to access all VIP
                        if (userInfo.RolesObj.Any(x => x.RoleCode == Constant.Authentication.TaxPayer.VIPAllBranch))
                        {
                            blnIsValid = true;
                        }
                        else
                        {
                            // Compare if TP branch contains User Branch
                            if (userInfo.RolesObj.Any(x => x.RoleCode == Constant.Authentication.TaxPayer.VIPOwnBranch)
                                && CompareUserBranchID(lstBranch, intCWPenaksiranCPID,
                                                       intCWPenaksiranCKHTID, intCWPungutanCPID, intCWPungutanCKHTID, intCWGuamanSivilID))
                            {
                                blnIsValid = true;
                            }
                        }
                    }
                    else
                    {
                        // Check if User is able to access all  TP
                        if (userInfo.RolesObj.Any(x => x.RoleCode == Constant.Authentication.TaxPayer.BiasaAllBranch))
                        {
                            blnIsValid = true;
                        }
                        else
                        {
                            // Compareif TP branch contains User Branch
                            if (userInfo.RolesObj.Any(x => x.RoleCode == Constant.Authentication.TaxPayer.BiasaOwnBranch)
                                && CompareUserBranchID(lstBranch, intCWPenaksiranCPID,
                                                       intCWPenaksiranCKHTID, intCWPungutanCPID, intCWPungutanCKHTID, intCWGuamanSivilID))
                            {
                                blnIsValid = true;
                            }
                        }
                    }
                    break;

                case Constant.TableType.Activity:
                    if (strVIPCode == "1") // Is VIP
                    {
                        // Check if User is able to access all VIP
                        if (userInfo.RolesObj.Any(x => x.RoleCode == Constant.Authentication.Activity.VIPAllBranch))
                        {
                            blnIsValid = true;
                        }
                        else
                        {
                            // Compareif TP branch contains User Branch
                            if (userInfo.RolesObj.Any(x => x.RoleCode == Constant.Authentication.Activity.VIPOwnBranch)
                                && CompareUserBranchID(lstBranch, intCWPenaksiranCPID,
                                                       intCWPenaksiranCKHTID, intCWPungutanCPID, intCWPungutanCKHTID, intCWGuamanSivilID))
                            {
                                blnIsValid = true;
                            }
                        }
                    }
                    else
                    {
                        // Check if User is able to access all  TP
                        if (userInfo.RolesObj.Any(x => x.RoleCode == Constant.Authentication.Activity.BiasaAllBranch))
                        {
                            blnIsValid = true;
                        }
                        else
                        {
                            // Compareif TP branch contains User Branch
                            if (userInfo.RolesObj.Any(x => x.RoleCode == Constant.Authentication.Activity.BiasaOwnBranch)
                                && CompareUserBranchID(lstBranch, intCWPenaksiranCPID,
                                                       intCWPenaksiranCKHTID, intCWPungutanCPID, intCWPungutanCKHTID, intCWGuamanSivilID))
                            {
                                blnIsValid = true;
                            }
                        }
                    }
                    break;
                default:
                    break;
            }

            return blnIsValid;
        }


        public static bool CompareUserBranchID(List<BranchListViewModel> lstBranch, int intCWPenaksiranCPID, int intCWPenaksiranCKHTID,
                                                    int intCWPungutanCPID, int intCWPungutanCKHTID,
                                                    int intCWGuamanSivilID)
        {
            bool blnIsValid = false;

            blnIsValid = lstBranch.Any(x => x.BranchLookupID == intCWPenaksiranCPID || x.BranchLookupID == intCWPenaksiranCKHTID
                                || x.BranchLookupID == intCWPungutanCPID || x.BranchLookupID == intCWPungutanCKHTID
                                || x.BranchLookupID == intCWGuamanSivilID);

            //blnIsValid = new[] { intCWPenaksiranCPID, intCWPenaksiranCKHTID, intCWPungutanCPID, intCWPungutanCKHTID, intCWGuamanSivilID }
            //             .Any(x => x == intUserBranchID);

            return blnIsValid;
        }

        public static string GetEnumDescription(Enum value)
        {
            FieldInfo fi = value.GetType().GetField(value.ToString());

            DescriptionAttribute[] attributes =
                (DescriptionAttribute[])fi.GetCustomAttributes(
                typeof(DescriptionAttribute),
                false);

            if (attributes != null &&
                attributes.Length > 0)
                return attributes[0].Description;
            else
                return value.ToString();
        }

        public static byte[] ExportExcel(DataTable dtbl)
        {
            using (XLWorkbook wb = new XLWorkbook())
            {
                //Outbound/HCL Email
                if (dtbl.Columns.Contains("CreatedDatetimeSort"))
                    dtbl.Columns.Remove("CreatedDatetimeSort");

                if (dtbl.Columns.Contains("JenisKempenID"))
                    dtbl.Columns.Remove("JenisKempenID");

                if (dtbl.Columns.Contains("DataID"))
                    dtbl.Columns.Remove("DataID");

                if (dtbl.Columns.Contains("StatusID"))
                    dtbl.Columns.Remove("StatusID");

                if (dtbl.Columns.Contains("EmailDataID"))
                    dtbl.Columns.Remove("EmailDataID");

                if (dtbl.Columns.Contains("EmailBlastStatusID"))
                    dtbl.Columns.Remove("EmailBlastStatusID");

                //TP, Act, Case, Task
                if (dtbl.Columns.Contains("ID"))
                    dtbl.Columns.Remove("ID");

                if (dtbl.Columns.Contains("TPID"))
                    dtbl.Columns.Remove("TPID");

                if (dtbl.Columns.Contains("ActivityID"))
                    dtbl.Columns.Remove("ActivityID");

                if (dtbl.Columns.Contains("CaseID"))
                    dtbl.Columns.Remove("CaseID");

                if (dtbl.Columns.Contains("CaseStatusIndicator"))
                    dtbl.Columns.Remove("CaseStatusIndicator");

                if (dtbl.Columns.Contains("TPCreatedDateTime"))
                    dtbl.Columns.Remove("TPCreatedDateTime");

                if (dtbl.Columns.Contains("ActCreatedDateTime"))
                    dtbl.Columns.Remove("ActCreatedDateTime");

                if (dtbl.Columns.Contains("CaseCreatedDatetime"))
                    dtbl.Columns.Remove("CaseCreatedDatetime");

                //Massage Status
                if (dtbl.Columns.Contains("ActStatusID"))
                {
                    dtbl.Columns.Add("ActStatusDesc", typeof(string));
                    foreach (DataRow dr in dtbl.Rows)
                    {
                        if (dr["ActStatusID"] != null)
                        {
                            if (dr["ActStatusID"].ToString() == "261")
                                dr["ActStatusDesc"] = "Belum Selesai";

                            if (dr["ActStatusID"].ToString() == "262")
                                dr["ActStatusDesc"] = "Selesai";
                        }
                    }
                    dtbl.Columns.Remove("ActStatusID");
                }

                if (dtbl.Columns.Contains("CaseStatusLevel1ID"))
                {
                    dtbl.Columns.Add("CaseStatusLevel1Desc", typeof(string));
                    foreach (DataRow dr in dtbl.Rows)
                    {
                        if (dr["CaseStatusLevel1ID"] != null)
                        {
                            if (dr["CaseStatusLevel1ID"].ToString() == "1")
                                dr["CaseStatusLevel1Desc"] = "Selesai";

                            if (dr["CaseStatusLevel1ID"].ToString() == "2")
                                dr["CaseStatusLevel1Desc"] = "Belum Selesai";
                        }
                    }
                    dtbl.Columns.Remove("CaseStatusLevel1ID");
                }

                wb.Worksheets.Add(dtbl, "Sheet 1");

                using (MemoryStream MyMemoryStream = new MemoryStream())
                {
                    wb.SaveAs(MyMemoryStream);
                    return MyMemoryStream.ToArray();
                }
            }

        }

        public static bool ConvertStringToBool(string value)
        {
            if(value == Resources.Messages.TrueDescription)
            {
                return true;
            }
            else if (value == Resources.Messages.FalseDescription)
            {
                return false;
            }
            else
            {
                return true;
            }

        }

    }
}
