using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Configuration;

namespace boilerplate.Models
{
    public class Functions
    {
        public List<T> ReadJsonFile<T>(string filePath)
        {
            try
            {
                string jsonData = System.IO.File.ReadAllText(filePath);
                List<T> dataList = JsonConvert.DeserializeObject<List<T>>(jsonData);
                return dataList;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error reading JSON file: {ex.Message}");
                return new List<T>();
            }
        }

        public string ConvertToPersianDate(DateTime? _Datetime, bool Hour = true)
        {
            string _DateTime = string.Empty;
            try
            {
                if (_Datetime.HasValue)
                {
                    var _Date = _Datetime.Value;
                    PersianCalendar pc = new PersianCalendar();
                    _DateTime = $"{pc.GetYear(_Date)}/{pc.GetMonth(_Date)}/{pc.GetDayOfMonth(_Date)}";
                    if (Hour) { _DateTime += $" {pc.GetHour(_Date)}:{pc.GetMinute(_Date)}:{pc.GetSecond(_Date)}"; }
                }
            }
            catch { }
            return _DateTime;
        }
        public DateTime? ConvertFromPersianDate(string _date)
        {
            try
            {
                if (!string.IsNullOrEmpty(_date))
                {
                    return DateTime.Parse(_date, new CultureInfo("fa-IR"));
                }
            }
            catch { }
            return null;
        }

        public string CalcuteOrderDate(string DateGmt, bool JustDate = false)
        {
            try
            {
                DateTime DateCreatedGmt = DateTime.Parse(DateGmt);
                DateTime Now = DateTime.Now;
                if (JustDate || Now > DateCreatedGmt.AddDays(1))
                {
                    PersianCalendar pc = new PersianCalendar();
                    string[] PersianMonth = { "", "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", };
                    //return $"{PersianMonth[pc.GetMonth(DateCreatedGmt)]} {pc.GetDayOfMonth(DateCreatedGmt)}, {pc.GetYear(DateCreatedGmt)}";
                    return $"{pc.GetDayOfMonth(DateCreatedGmt)} {PersianMonth[pc.GetMonth(DateCreatedGmt)]} {pc.GetYear(DateCreatedGmt)}";
                }
                else
                {
                    string NewTime = $"{(Now - DateCreatedGmt).Seconds} ثانیه پیش";
                    int Minutes = (Now - DateCreatedGmt).Minutes;
                    int Hours = (Now - DateCreatedGmt).Hours;
                    if (Hours > 0)
                    {
                        NewTime = $"{Hours} ساعت و {Minutes} دقیقه پیش";
                    }
                    else if (Minutes > 0)
                    {
                        NewTime = $"{Minutes} دقیقه پیش";
                    }
                    return NewTime;
                }
            }
            catch
            {
                return DateGmt;
            }
        }
        public string CalcuteDiscount(bool OnSale, string DateOnSaleFrom, string DateOnSaleTo, string RegularPrice, string SalePrice)
        {
            string Discount = "0";
            try
            {
                if (OnSale  && !string.IsNullOrEmpty(DateOnSaleFrom) && !string.IsNullOrEmpty(DateOnSaleTo) && !string.IsNullOrEmpty(SalePrice))
                {
                    try
                    {
                        DateTime Now = DateTime.Now;
                        DateTime From = DateTime.Parse(DateOnSaleFrom);
                        DateTime To = DateTime.Parse(DateOnSaleTo);
                        if (Now >= From && Now <= To)
                        {
                            Discount = CalcuteDiscount(RegularPrice, SalePrice);
                        }
                    }
                    catch { }
                }
                else if (!string.IsNullOrEmpty(SalePrice))
                {
                    Discount = CalcuteDiscount(RegularPrice, SalePrice);
                }
            }
            catch { }
            return Discount;
        }

        public string CalcuteDiscount(string Price1, string Price2)
        {
            string Discount = "0";
            try
            {
                decimal number1 = decimal.Parse(Price1);
                decimal number2 = decimal.Parse(Price2);

                decimal x = number1 / 100;
                decimal y = number1 - number2;
                Discount = Math.Round(y / x).ToString();
            }
            catch { }
            return Discount;
        }

        public bool IsValidEmail(string email)
        {
            if (email.Trim().EndsWith(".")) { return false; }
            try
            {
                var addr = new System.Net.Mail.MailAddress(email);
                return addr.Address == email;
            }
            catch { return false; }
        }

        public string HashPassword(string Password)
        {
            SHA256 sHA = SHA256.Create();
            var PasswordBytes = Encoding.UTF8.GetBytes(Password);
            var Hash = sHA.ComputeHash(PasswordBytes);
            return Convert.ToBase64String(Hash);
        }

        public string GenerateToken(int Min = 28, int Max = 33)
        {
            Random random = new Random();
            int tokenLength = random.Next(Min, Max);
            string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            StringBuilder tokenBuilder = new StringBuilder();
            for (int i = 0; i < tokenLength; i++)
            {
                tokenBuilder.Append(chars[random.Next(chars.Length)]);
            }
            return tokenBuilder.ToString();
        }

        public string ReadSetting(string key)
        {
            try { return ConfigurationManager.AppSettings[key] ?? ""; }
            catch { return string.Empty; }
        }

        public string AddUpdateAppSettings(List<KeyValuePair<string, string>> KeyValue)
        {
            try
            {
                Configuration configFile = null;
                if (HttpContext.Current != null)
                {
                    configFile = WebConfigurationManager.OpenWebConfiguration("~");
                }
                else
                {
                    configFile = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                }
                var settings = configFile.AppSettings.Settings;
                foreach (var item in KeyValue)
                {
                    if (settings[item.Key] == null)
                    {
                        settings.Add(item.Key, item.Value);
                    }
                    else
                    {
                        settings[item.Key].Value = item.Value;
                    }
                }
                configFile.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection(configFile.AppSettings.SectionInformation.Name);
                return string.Empty;
            }
            catch (Exception ex) { return ex.Message + Environment.NewLine + ex.StackTrace; }
        }

        public string LeftTimeDate(DateTime dateTime)
        {
            try
            {
                const int SECOND = 1;
                const int MINUTE = 60 * SECOND;
                const int HOUR = 60 * MINUTE;
                const int DAY = 24 * HOUR;
                const int MONTH = 30 * DAY;

                var ts = new TimeSpan(DateTime.Now.Ticks - dateTime.Ticks);
                double delta = Math.Abs(ts.TotalSeconds);
                if (delta < 1 * MINUTE)
                    return ts.Seconds + " ثانیه پیش";

                if (delta < 2 * MINUTE)
                    return "1 دقیقه پیش";

                if (delta < 45 * MINUTE)
                    return ts.Minutes + " دقیقه پیش";

                if (delta < 90 * MINUTE)
                    return "1 ساعت پیش";

                if (delta < 24 * HOUR)
                    return ts.Hours + " ساعت پیش";

                if (delta < 48 * HOUR)
                    return "دیروز";

                if (delta < 30 * DAY)
                    return ts.Days + " روز پیش";

                if (delta < 12 * MONTH)
                {
                    int months = Convert.ToInt32(Math.Floor((double)ts.Days / 30));
                    return months <= 1 ? "1 ماه پیش" : months + " ماه پیش";
                }
                else
                {
                    int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
                    return years <= 1 ? "1 سال پیش" : years + " سال پیش";
                }
            }
            catch { return ""; }
        }

        public string GetDayOfWeek(DayOfWeek day)
        {
            switch (day)
            {
                case DayOfWeek.Sunday:
                    return "یکشنبه";
                case DayOfWeek.Monday:
                    return "دوشنبه";
                case DayOfWeek.Tuesday:
                    return "سه شنبه";
                case DayOfWeek.Wednesday:
                    return "چهارشنبه";
                case DayOfWeek.Thursday:
                    return "پنجشنبه";
                case DayOfWeek.Friday:
                    return "جمعه";
                case DayOfWeek.Saturday:
                    return "شنبه";
                default:
                    return string.Empty;
            }
        }

        public string GetDateWithPersianMonth(DateTime dateTime, bool WithDate = true)
        {
            PersianCalendar pc = new PersianCalendar();
            string[] PersianMonth = { "", "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", };
            if (WithDate)
            {
                return $"{pc.GetDayOfMonth(dateTime)} {PersianMonth[pc.GetMonth(dateTime)]} {pc.GetYear(dateTime)}";
            }
            else
            {
                return PersianMonth[pc.GetMonth(dateTime)];
            }
        }

        public string GetPersianMonthName(DateTime date)
        {
            CultureInfo persianCulture = new CultureInfo("fa-IR");
            PersianCalendar persianCalendar = new PersianCalendar();
            string persianMonthName = persianCulture.DateTimeFormat.GetMonthName(persianCalendar.GetMonth(date));
            return persianMonthName;
        }

        public string ShortDescription(string Description, int Length = 115)
        {
            if (Description.Length > Length) { Description = Description.Substring(0, Length); }
            return Description + " [...]";
        }

        public bool HasAccess(string UserAccess, string Access)
        {
            try
            {
                if (!string.IsNullOrEmpty(UserAccess))
                {
                    List<string> AccessList = $"{UserAccess}".Split(',').ToList();
                    return AccessList.Contains("All") || AccessList.Contains(Access);
                }
            }
            catch { }
            return false;
        }

        public bool HasAccess(string UserAccess, string[] AccessList)
        {
            try
            {
                if (!string.IsNullOrEmpty(UserAccess))
                {
                    List<string> UserAccessList = $"{UserAccess}".Split(',').ToList();
                    return UserAccessList.Contains("All") || AccessList.Any(access => UserAccessList.Contains(access));
                }
            }
            catch { }
            return false;
        }

        public bool ValidateIPv4(string ipString)
        {
            if (string.IsNullOrWhiteSpace(ipString)) { return false; }
            string[] splitValues = ipString.Split('.');
            if (splitValues.Length != 4) { return false; }
            return splitValues.All(r => short.TryParse(r, out _));
        }

        public UserAccessModel CheckUserAccess(AuthModel model, string[] RoleList = null, string[] AccessList = null)
        {
            boilerplateEntities db = new boilerplateEntities();
            UserAccessModel statusModel = new UserAccessModel() { Id = 0 };
            if (model.UserId == 0 || string.IsNullOrEmpty(model.Token)) { return statusModel; }
            else
            {
                AccessList = AccessList ?? new string[0];
                RoleList = RoleList ?? new string[0];
                bool Access = true;
                bool Role = true;
                statusModel = db.Users
                    .Where(x => x.User_Id == model.UserId && x.User_Token == model.Token && x.User_Status == 1)
                    .Select(x => new UserAccessModel
                    {
                        Id = x.User_Id,
                        Role = x.User_Role,
                        Access = x.User_Access,
                    }).FirstOrDefault();

                if (statusModel != null)
                {
                    if (AccessList.Length > 0)
                    {
                        string[] access = statusModel.Access.Split(',');
                        Access = AccessList.Intersect(access).Count() > 0;
                    }
                    if (RoleList.Length > 0)
                    {
                        string[] role = statusModel.Role.Split(',');
                        Role = RoleList.Intersect(role).Count() > 0;
                    }
                    if (!(Role && Access)) { statusModel.Id = 0; }
                }
                else { statusModel = new UserAccessModel() { Id = 0 }; }
                return statusModel;
            }
        }
        //public async Task RecordLogAsync(int user, string message = null, string type = null)
        //{
        //    boilerplateEntities db = new boilerplateEntities();
        //    var now = DateTime.Now;
        //    db.Logs.Add(new Log
        //    {
        //        Log_User = user,
        //        Log_Message = message,
        //        Log_Type = type,
        //        Log_Date = now,
        //        Log_DateFa = ConvertToPersianDate(now),
        //    });
        //    await db.SaveChangesAsync();
        //}

        internal async Task RecordLogAsync(object user_Id, string m, string v)
        {
            throw new NotImplementedException();
        }
    }
}