using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
using Google.Protobuf.WellKnownTypes;
using Microsoft.AspNetCore.Components.Forms;

namespace FrontOffice.Main.Utilities;

public static class Extensions
{
    public static CultureInfo GetPersianCulture()
    {
        var culture = new CultureInfo("fa-IR");
        DateTimeFormatInfo formatInfo = culture.DateTimeFormat;
        formatInfo.AbbreviatedDayNames = new[] { "ی", "د", "س", "چ", "پ", "ج", "ش" };
        formatInfo.DayNames = new[] { "یکشنبه", "دوشنبه", "سه شنبه", "چهار شنبه", "پنجشنبه", "جمعه", "شنبه" };
        var monthNames = new[]
        {
            "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن",
            "اسفند",
            "",
        };
        formatInfo.AbbreviatedMonthNames =
            formatInfo.MonthNames =
                formatInfo.MonthGenitiveNames = formatInfo.AbbreviatedMonthGenitiveNames = monthNames;
        formatInfo.AMDesignator = "ق.ظ";
        formatInfo.PMDesignator = "ب.ظ";
        formatInfo.ShortDatePattern = "yyyy/MM/dd";
        formatInfo.LongDatePattern = "dddd, dd MMMM,yyyy";
        formatInfo.FirstDayOfWeek = DayOfWeek.Saturday;
        Calendar cal = new PersianCalendar();
        FieldInfo fieldInfo = culture.GetType().GetField("calendar", BindingFlags.NonPublic | BindingFlags.Instance);
        if (fieldInfo != null)
            fieldInfo.SetValue(culture, cal);
        FieldInfo info = formatInfo.GetType().GetField("calendar", BindingFlags.NonPublic | BindingFlags.Instance);
        if (info != null)
            info.SetValue(formatInfo, cal);
        culture.NumberFormat.NumberDecimalSeparator = "/";
        culture.NumberFormat.DigitSubstitution = DigitShapes.NativeNational;
        culture.NumberFormat.NumberNegativePattern = 0;
        return culture;
    }
    public static string ExtractUserFriendlyMessage(this string errorMessage)
    {
        // کلیدواژه‌ای که بعد از آن بخش مورد نظر شروع می‌شود
        string keyword = "Exception:";

        // بررسی وجود کلیدواژه در پیام خطا
        int keywordIndex = errorMessage.IndexOf(keyword);

        if (keywordIndex >= 0)
        {
            // استخراج بخش بعد از کلیدواژه
            string userFriendlyMessage = errorMessage.Substring(keywordIndex + keyword.Length).Trim();
            if (userFriendlyMessage.EndsWith(")"))
            {
                userFriendlyMessage = userFriendlyMessage.Substring(0, userFriendlyMessage.Length - 2);
            }
            return userFriendlyMessage;
        }

        // اگر کلیدواژه وجود نداشت، کل پیام خطا برگردانده شود
        return errorMessage;
    }
    public static string DiffDateTime(this DateTime dateTime)
    {
        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 == 1 ? "لحظه ای قبل" : ts.Seconds + " ثانیه قبل";
        }
        if (delta < 2 * MINUTE)
        {
            return "یک دقیقه قبل";
        }
        if (delta < 45 * MINUTE)
        {
            return ts.Minutes + " دقیقه قبل";
        }
        if (delta < 90 * MINUTE)
        {
            return "یک ساعت قبل";
        }
        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 ? "یک ماه قبل" : months + " ماه قبل";
        }
        int years = Convert.ToInt32(Math.Floor((double)ts.Days / 365));
        return years <= 1 ? "یک سال قبل" : years + " سال قبل";
    }
    public static string StripHtmlTags(this string html)
    {
        if (string.IsNullOrEmpty(html))
            return string.Empty;

        // حذف تمامی تگ‌های HTML
        string textOnly = Regex.Replace(html, "<.*?>", string.Empty);

        // تبدیل کاراکترهای HTML به متن معمولی (مثلاً &nbsp; -> فضای خالی)
        textOnly = WebUtility.HtmlDecode(textOnly);

        return textOnly.Trim();
    }
    public static string ConfuseId(this string? value)
    {
        if (!string.IsNullOrWhiteSpace(value) && value.Length > 6)
            return string.Concat(value[..3], "*****", value.AsSpan(value.Length - 3, 3));
        else if (!string.IsNullOrWhiteSpace(value) && value.Length > 4)
            return string.Concat(value[..2], "*****", value.AsSpan(value.Length - 2, 2));
        else
            return value;
    }
    public static Timestamp DateTimeToTimestamp(this DateTime dateTime)
    {
        return Timestamp.FromDateTime(DateTime.SpecifyKind(dateTime, DateTimeKind.Utc));
    }
    public static Timestamp? DateTimeToTimestamp(this DateTime? dateTime)
    {
        if (dateTime == null)
            return null;

        return Timestamp.FromDateTime(DateTime.SpecifyKind(dateTime.Value, DateTimeKind.Utc));
    }
    //public static string ToThousands(this string numberString)
    //{
    //    if (double.TryParse(numberString, out var number))
    //    {
    //        return string.Format("{0:#,###0.################}", number);
    //    }

    //    return numberString;
    //}

    public static string ToThousands(this string numberString)
    {
        if (double.TryParse(numberString, out var number))
        {
            // حذف اعشار
            var integerPart = Math.Truncate(number);

            // فرمت‌بندی سه رقمی
            return string.Format("{0:#,###0}", integerPart);
        }
        else
        {
            if (numberString.Split('.').Length > 1)
                return numberString.Split('.')[0];
        }

        return numberString;
    }
    public static string ToThousands(this long number)
    {
        return number.ToString().ToThousands();
    }

    public static string ToThousands(this long? number)
    {
        return number?.ToString().ToThousands();
    }

    public static string ToThousands(this int number)
    {
        return number.ToString().ToThousands();
    }

    public static string ToThousands(this int? number)
    {
        return number?.ToString().ToThousands();
    }

    public static string ToThousands(this float number)
    {
        return number.ToString().ToThousands();
    }
    public static string ToThousands(this float? number)
    {
        return number?.ToString().ToThousands();
    }

    public static string ToThousands(this double number)
    {
        return number.ToString().ToThousands();
    }

    public static string ToThousands(this double? number)
    {
        return number?.ToString().ToThousands();
    }
    public static long ToIRT(this long number)
    {
        return (long)(number * 0.1);
    }
    public static string ToCurrencyUnitIRR(this string str) => str + " ریال";
    public static string ToCurrencyUnitIRT(this string str) => str + " تومان";
    public static string FaToAr(this string str) => str.Replace("ک", "ك").Replace("ی", "ي");
    public static string ArToFa(this string str) => str.Replace("ك", "ک").Replace("ي", "ی");

    public static string Truncate(this string value, int maxLength, bool isAppendDots = false)
    {
        if (string.IsNullOrEmpty(value)) return value;
        return value.Length <= maxLength ? value : isAppendDots ? value.Substring(0, maxLength) + "..." : value.Substring(0, maxLength);
    }

    public static string PersianToEnglish(this string persianStr)
    {
        return persianStr.Replace("۰", "0")
            .Replace("۱", "1")
            .Replace("۲", "2")
            .Replace("۳", "3")
            .Replace("۴", "4")
            .Replace("۵", "5")
            .Replace("۶", "6")
            .Replace("۷", "7")
            .Replace("۸", "8")
            .Replace("۹", "9");
    }

    public static string GetDisplayName(this System.Enum enumValue)
    {
        return enumValue.GetType()
                        .GetMember(enumValue.ToString())
                        .First()
                        .GetCustomAttribute<DisplayAttribute>()
                        .GetName();
    }

    public static async Task<string> ConvertIBrowserFileToBase64(this IBrowserFile? file)
    {
        if (file == null)
        {
            return string.Empty;
        }

        const long maxAllowedSize = 1024 * 1024 * 200;
        var imageBuffers = new byte[file.Size];
        using (var stream = file.OpenReadStream(maxAllowedSize))
        {
            await stream.ReadAsync(imageBuffers);
        }
        return $"data:{file.ContentType};base64," + Convert.ToBase64String(imageBuffers);
    }

    public static string GetNumberToPersianString(this string txt)
    {
        string RET = " ", STRVA = " ";
        string[] MainStr = STR_To_Int(txt);
        int Q = 0;
        for (int i = MainStr.Length - 1; i >= 0; i--)
        {
            STRVA = " ";
            if (RET != " " && RET != null)
                STRVA = " و ";
            if (string.IsNullOrWhiteSpace(Convert_STR(GETCountStr(MainStr[i]), Q)))
                RET = Convert_STR(GETCountStr(MainStr[i]), Q) + RET;
            else
                RET = Convert_STR(GETCountStr(MainStr[i]), Q) + STRVA + RET;

            Q++;
        }

        if (RET == " " || RET == null || RET == "  ")
            RET = "صفر";
        return RET;
    }
    private static string[] STR_To_Int(string STR)
    {
        STR = GETCountStr(STR);
        string[] RET = new string[STR.Length / 3];
        int Q = 0;
        for (int I = 0; I < STR.Length; I += 3)
        {
            RET[Q] = STR.Substring(I, 3);
            Q++;
        }

        return RET;
    }

    private static string GETCountStr(string STR)
    {
        string RET = STR;
        int LEN = (STR.Length / 3 + 1) * 3 - STR.Length;
        if (LEN < 3)
        {
            for (int i = 0; i < LEN; i++)
            {
                RET = "0" + RET;
            }
        }

        if (RET == "")
            return "000";
        return RET;
    }

    private static string Convert_STR(string INT, int Count)
    {
        string RET = "";
        //یک صد
        if (Count == 0)
        {
            if (INT.Substring(1, 1) == "1" && INT.Substring(2, 1) != "0")
            {
                RET = GET_Number(3, Convert.ToInt32(INT.Substring(0, 1)), " ") + GET_Number(1, Convert.ToInt32(INT.Substring(2, 1)), "");
            }
            else
            {
                string STR = GET_Number(0, Convert.ToInt32(INT.Substring(2, 1)), "");
                RET = GET_Number(3, Convert.ToInt32(INT.Substring(0, 1)), GET_Number(2, Convert.ToInt32(INT.Substring(1, 1)), "") + STR) + GET_Number(2, Convert.ToInt32(INT.Substring(1, 1)), STR) + GET_Number(0, Convert.ToInt32(INT.Substring(2, 1)), "");
            }
        }
        //هزار
        else if (Count == 1)
        {
            RET = Convert_STR(INT, 0);
            if (string.IsNullOrWhiteSpace(RET))
                return string.Empty;
            RET += " هزار";
        }
        //میلیون
        else if (Count == 2)
        {
            RET = Convert_STR(INT, 0);
            if (string.IsNullOrWhiteSpace(RET))
                return string.Empty;
            RET += " میلیون";
        }
        //میلیارد
        else if (Count == 3)
        {
            RET = Convert_STR(INT, 0);
            if (string.IsNullOrWhiteSpace(RET))
                return string.Empty;
            RET += " میلیارد";
        }
        //میلیارد
        else if (Count == 4)
        {
            RET = Convert_STR(INT, 0);
            if (string.IsNullOrWhiteSpace(RET))
                return string.Empty;
            RET += " تیلیارد";
        }
        //میلیارد
        else if (Count == 5)
        {
            RET = Convert_STR(INT, 0);
            if (string.IsNullOrWhiteSpace(RET))
                return string.Empty;
            RET += " بیلیارد";
        }
        else
        {
            RET = Convert_STR(INT, 0);
            if (string.IsNullOrWhiteSpace(RET))
                return string.Empty;
            RET += Count.ToString();
        }

        return RET;
    }

    private static string GET_Number(int Count, int Number, string VA)
    {
        string RET = "";

        if (VA != "" && VA != null)
        {
            VA = " و ";
        }

        if (Count == 0 || Count == 1)
        {
            bool IsDah = Convert.ToBoolean(Count);
            string[] MySTR = new string[10];
            MySTR[1] = IsDah ? "یازده" : "یک" + VA;
            MySTR[2] = IsDah ? "دوازده" : "دو" + VA;
            MySTR[3] = IsDah ? "سیزده" : "سه" + VA;
            MySTR[4] = IsDah ? "چهارده" : "چهار" + VA;
            MySTR[5] = IsDah ? "پانزده" : "پنج" + VA;
            MySTR[6] = IsDah ? "شانزده" : "شش" + VA;
            MySTR[7] = IsDah ? "هفده" : "هفت" + VA;
            MySTR[8] = IsDah ? "هجده" : "هشت" + VA;
            MySTR[9] = IsDah ? "نوزده" : "نه" + VA;
            return MySTR[Number];
        }
        else if (Count == 2)
        {
            string[] MySTR = new string[10];
            MySTR[1] = "ده";
            MySTR[2] = "بیست" + VA;
            MySTR[3] = "سی" + VA;
            MySTR[4] = "چهل" + VA;
            MySTR[5] = "پنجاه" + VA;
            MySTR[6] = "شصت" + VA;
            MySTR[7] = "هفتاد" + VA;
            MySTR[8] = "هشتاد" + VA;
            MySTR[9] = "نود" + VA;
            return MySTR[Number];
        }
        else if (Count == 3)
        {
            string[] MySTR = new string[10];
            MySTR[1] = "یکصد" + VA;
            MySTR[2] = "دویست" + VA;
            MySTR[3] = "سیصد" + VA;
            MySTR[4] = "چهارصد" + VA;
            MySTR[5] = "پانصد" + VA;
            MySTR[6] = "ششصد" + VA;
            MySTR[7] = "هفتصد" + VA;
            MySTR[8] = "هشتصد" + VA;
            MySTR[9] = "نهصد" + VA;
            return MySTR[Number];
        }

        return RET;
    }
}