import matplotlib.pyplot as plt
import numpy as np
import matplotlib.colors as mcolors
import pandas as pd
from collections import defaultdict

def percent_to_number(value):
    # إذا كانت القيمة نص
    if isinstance(value, str):
        # إزالة أي مسافات
        value = value.strip()
        # إذا كانت تحتوي على %
        if "%" in value:
            return float(value.replace("%", ""))
        else:
            return float(value)
    # إذا كانت القيمة رقم (int أو float)
    elif isinstance(value, (int, float)):
        return float(value)
    else:
        # قيمة افتراضية إذا كان النوع غير متوقع
        return 0.0

def auto_split(text, max_len=12):
        # إذا كان النص قصير لا يحتاج تقسيم
        if len(text) <= max_len:
            return text
        
        # تقسيم النص إلى كلمات
        words = text.split()
        lines = []
        current_line = ""
        
        for word in words:
            if len(current_line + " " + word) <= max_len:
                current_line += " " + word if current_line else word
            else:
                lines.append(current_line)
                current_line = word
        lines.append(current_line)
        
        # دمج الأسطر مع فاصل سطر جديد
        return "\n".join(lines)

def make_lighter(color, factor=0.3):
    rgb = mcolors.to_rgb(color)
    lighter_rgb = [(1 - (1 - c) * (1 - factor)) for c in rgb]
    return lighter_rgb

def ordinal_suffix(n: int) -> str:
    # الحالات الخاصة للأرقام التي تنتهي بـ 11, 12, 13
    if 11 <= n % 100 <= 13:
        suffix = "th"
    else:
        # اختيار اللاحقة حسب الرقم الأخير
        last_digit = n % 10
        if last_digit == 1:
            suffix = "st"
        elif last_digit == 2:
            suffix = "nd"
        elif last_digit == 3:
            suffix = "rd"
        else:
            suffix = "th"
    return f"{n:.0f}{suffix}"

def Player(dataset,
           #العنوان الرئيسي للرسم
           First_tittel="Anis",
           First_tittel_color = "#570101",
           First_tittel_size = 12,

           Secend_tittel="",
           Secend_tittel_color = "#570101",
           Secend_tittel_size = 10,
           
           bottom_circle = 10,

           Metric_size = 9,
           Metric_color = "black",
           Metric_distance = 108,
           Metric_color_option = False,

           ):
    data = pd.DataFrame(dataset)

    #تجهيز قائمة للاعبين بدون تكرار
    selected_players = data["Player"].unique()

    if len(selected_players) > 0:
        # اختيار اللاعب الأول من القائمة
        player_name = selected_players[0]

        # تصفية البيانات للاعب المحدد
        player_data = data[data["Player"] == player_name]

        # ترتيب البيانات حسب الصنف
        player_data = player_data.sort_values(by="Category")

        #تخزين البيانات في قوائم منفصلة
        metrics = player_data["Metric"].astype(str).tolist()
        values = player_data["Value"].tolist()
        colors = player_data["Color"].astype(str).tolist()
        categories = player_data["Category"].astype(str).tolist()

        #حساب عدد الاحصائيات
        N = len(metrics)

        #حساب الزوايا لكل إحصائية
        angles = np.linspace(0, 2*np.pi, N+1)

        #رسم المخطط
        fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))

        # إعدادات الشكل
        ax.set_ylim(0, 110)
        ax.set_xticks([])
        ax.set_yticks([20, 40, 60, 80, 100])
        ax.set_yticklabels(["20", "40", "60", "80", "100"], fontsize=0)

        #إخفاء خط الدائرة الخارجية
        ax.spines["polar"].set_visible(False)

        #رسم الدوائر الدخلية للمخطط
        ax.grid(color="gray", linestyle="--", linewidth=0.7, alpha=0.6)

        #إخفاء الدوائر الدخلية للمخطط
        ax.grid(False)

        #رسم الدوائر الخارجية للمخطط
        theta = np.linspace(0, 2*np.pi, 500)
        ax.plot(theta, [100]*500, color="black", linewidth=0)

        #رسم الخطوط بين كل إحصائية
        for angle in angles[:-1]:
            ax.plot([angle, angle], [bottom_circle, 100+bottom_circle],
            color="white", linestyle="-", linewidth=1)

        # رسم الأجزاء الخارجية والداخلية لكل إحصائية
        for i in range(N):

            # حساب الزاوية لكل فئة
            start_angle = angles[i]
            end_angle = angles[i+1]
            mid_angle = (start_angle + end_angle) / 2

            # تحويل القيم إلى أرقام
            val = percent_to_number(values[i])

            # تحديد اللون
            base_color = colors[i]

            # الجزء الخارجي (لون فاتح)
            ax.bar(mid_angle, 100, width=end_angle-start_angle, 
                color=make_lighter(base_color,0.8), edgecolor="white" ,bottom=bottom_circle)
            
            # الجزء الداخلي (القيمة الفعلية)
            ax.bar(mid_angle, val, width=end_angle-start_angle, 
                color=base_color, edgecolor="white", bottom=bottom_circle)
            
            # كتابة القيمة
            ax.text(mid_angle, val + bottom_circle, f"{val:02.0f}", ha="center", va="center", fontsize=8,fontweight="bold", color="black",bbox=dict(facecolor=make_lighter(base_color,0.25), edgecolor="black", boxstyle="round,pad=0.2"))
        
            # حساب زاوية دوران اسم الاحصائيات
            rotation_angle = np.degrees(mid_angle) + 90
            if 0< np.degrees(mid_angle) < 180:
                rotation_angle += 180

            #تحديد لون اسم الاحصائيات بناءً على الخيار المحدد
            if Metric_color_option == True:
                Metric_color = base_color

            # كتابة الاحصائيات
            ax.text(mid_angle, (Metric_distance +bottom_circle), auto_split(metrics[i], max_len=12), ha="center", va="center", fontsize=Metric_size, fontweight="bold", rotation=rotation_angle, rotation_mode="anchor",color=Metric_color)


        # كتابة العنوان الرئيسي
        fig.text(0.515, 0.965, First_tittel, size=First_tittel_size, ha="center", color=First_tittel_color, fontweight="bold")

        # كتابة العنوان الفرعي
        fig.text(0.515, 0.930, Secend_tittel, size=Secend_tittel_size, ha="center", color=Secend_tittel_color, fontweight="bold")

        # تجهيز قائمة الفئات والألوان لأسطورة المخطط
        categories = list(dict(zip(categories, colors)).items())
        
        # إنشاء عناصر الأسطورة بناءً على الفئات والألوان
        legend_handles = [  plt.Line2D([0], [0], color="none", label=label) for label, _ in categories]

        # عرض الأسطورة
        legend = fig.legend(
            handles=legend_handles,
            loc='upper center',
            bbox_to_anchor=(0.5, 0.96),
            ncol=len(categories),
            frameon=False,
            fontsize=7,
            columnspacing=0
        )

        # ضبط لون النص في الأسطورة ليتناسب مع الألوان المستخدمة
        for text, (_, color) in zip(legend.get_texts(), categories):
            text.set_color(color)

        # عرض المخطط
        plt.show()


def Scatter(dataset,

            Title_x_size = 6,
            Title_x_bold = "bold",
            Title_x_color = "#FF0000",
            linewidth_x = 0.85,

            Title_y_size = 6,
            Title_y_bold = "bold",
            Title_y_color = "#0004FF",
            linewidth_y = 0.85,

            color_1 = "#15BB15",
            color_2 = "#271CC5",
            color_3 = "#C51C1C",
            color_4 = "gray",

            marker_size = 8,
            text_marker_size = 8,
            marker = None,

            x_axis_size = 6,
            y_axis_size = 6,

            y_axis_color = "black",
            x_axis_color = "black"
            ):
    # العمود الأول للأسماء
    names = dataset.iloc[:, 0].tolist()

    # العمود الثاني  x
    x = dataset.iloc[:, 1].astype(int).tolist()

    # العمود الثالث  y
    y = dataset.iloc[:, 2].astype(int).tolist()
    # الحصول على أسماء الأعمدة
    column_names = dataset.columns.tolist()
    # حساب المتوسطات
    a=sum(x) / len(x)

    b=sum(y) / len(y)

    # تجميع النقاط حسب الإحداثيات
    points = defaultdict(list)
    for xi, yi, label in zip(x, y, names):
        points[(xi, yi)].append(label)

    fig, ax = plt.subplots(figsize=(12,14))
    plt.subplots_adjust(
        left=0.1,   # 10% من العرض يترك كهوامش يسار
        right=0.9,  # 90% من العرض يترك كهوامش يمين
        top=0.9,    # 90% من الارتفاع يترك كهوامش أعلى
        bottom=0.1  # 10% من الارتفاع يترك كهوامش أسفل
    )

    for spine in plt.gca().spines.values():
        spine.set_edgecolor("lightgray")   # لون أفتح
        spine.set_linewidth(1.2)           # يمكن التحكم في السماكة أيضاً
        spine.set_alpha(0.7) 
        
    ax.tick_params(axis='x', labelsize=x_axis_size, colors=x_axis_color) 
    ax.tick_params(axis='y', labelsize=y_axis_size, colors=y_axis_color)

    # خط عمودي عند x = a
    plt.axvline(x=a, linestyle='--', color=Title_x_color, linewidth=linewidth_x)

    # خط أفقي عند y = b
    plt.axhline(y=b, linestyle='--', color=Title_y_color, linewidth=linewidth_y)
    # رسم النقاط مع دمج الأسماء
    for (xi, yi), lbls in points.items():

        if xi >= a and yi >= b :
            ax.plot(xi, yi, marker=marker, color=color_1, markersize=marker_size)
            text = ", ".join(lbls)
            ax.text(xi, yi, text, fontsize=text_marker_size, color=color_1)

        elif xi >= a and yi < b :
            ax.plot(xi, yi, marker=marker, color=color_2, markersize=marker_size)
            text = ", ".join(lbls)
            ax.text(xi, yi, text, fontsize=text_marker_size, color=color_2)

        elif xi < a and yi < b :
            ax.plot(xi, yi, marker=marker, color=color_3, markersize=marker_size)
            text = ", ".join(lbls)
            ax.text(xi, yi, text, fontsize=text_marker_size, color=color_3)

        else:
            ax.plot(xi, yi, marker=marker, color=color_4, markersize=marker_size)
            text = ", ".join(lbls)
            ax.text(xi, yi, text, fontsize=text_marker_size, color=color_4)

        


    ax.set_xlabel(column_names[1], fontsize=Title_x_size, fontweight=Title_x_bold, color=Title_x_color)
    ax.set_ylabel(column_names[2], fontsize=Title_y_size, fontweight=Title_y_bold, color=Title_y_color)

    plt.show()

def Player_vs_Player(dataset,
                     
                     Player1_color="#FF9300",
                     Player2_color="#1A78CF",
                    #العنوان الرئيسي للرسم
                     First_tittel="Anis",
                     First_tittel_color = "#000000",
                     First_tittel_size = 12,
                    
                     Circle_size = 4,

                     Metric_size = 9,
                     Metric_distance = 110,
                     Metric_color = "black",

                     ):
    # استخراج اللاعبين بدون تكرار
    selected_players = dataset["Player"].unique()

    if len(selected_players) >= 2:

        player1 = selected_players[0]
        player2 = selected_players[1]



        # بيانات اللاعب الأول
        data1 = dataset[dataset["Player"] == player1].sort_values(by="Category")

        metrics = data1["Metric"].astype(str).tolist()
        values1 = data1["Value"].astype(float).tolist()


        # بيانات اللاعب الثاني
        data2 = dataset[dataset["Player"] == player2].sort_values(by="Category")
        values2 = data2["Value"].astype(float).tolist()

        N = len(metrics)
        angles = np.linspace(0, 2*np.pi, N+1)

        fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))

        # إعدادات الشكل
        ax.set_ylim(0, 110)
        ax.set_xticks([])
        ax.set_yticks([20, 40, 60, 80, 100])
        ax.set_yticklabels(["20", "40", "60", "80", "100"], fontsize=0)

        # إخفاء خط الدائرة الخارجية
        ax.spines["polar"].set_visible(False)
        
        # رسم الشبكة
        ax.grid(color="gray", linestyle="-", linewidth=0.7, alpha=0.3)

        # إخفاء الشبكة
        ax.grid(False)

        # رسم الدائرة الخارجية للمخطط
        theta = np.linspace(0, 2*np.pi, 500)
        ax.plot(theta, [100+Circle_size]*500, color="black", linewidth=1.2)

        # رسم الدائرة الداخلية للمخطط
        ax.plot(theta, [Circle_size]*500, color="black", linewidth=0.7)

        # رسم الخطوط بين الدوائر
        for angle in angles[:-1]:
            ax.plot([angle, angle], [Circle_size, 100+Circle_size], color="Black", linestyle="-", linewidth=1)

        for i in range(N):

            # حساب الزاوية لكل فئة
            start_angle = angles[i]
            end_angle = angles[i+1]
            mid_angle = (start_angle + end_angle) / 2

            # تحويل القيم إلى أرقام
            val1 = percent_to_number(values1[i])   
            val2 = percent_to_number(values2[i])

            # الجزء الخارجي (لون فاتح)
            ax.bar(mid_angle, 100, width=end_angle-start_angle, color="white", edgecolor="white")

            if val1 >= val2:

                # تحديد القيمة الأكبر والصغرى
                Max = val1
                Min = val2

                #تحديد لون الجزء الأكبر والصغرى
                Color_Max = Player1_color
                Color_Min = Player2_color

            else:

                # تحديد القيمة الأكبر والصغرى
                Max = val2
                Min = val1

                #تحديد لون الجزء الأكبر والصغرى
                Color_Max = Player2_color
                Color_Min = Player1_color

            # الجزء الداخلي (القيمة الأكبر)
            ax.bar(mid_angle, Max, width=end_angle-start_angle, color=Color_Max, edgecolor="black",bottom=Circle_size)
            ax.text(mid_angle,Max , f"{Max:02.0f}%", ha="center", va="center", fontsize=8,fontweight="bold",
                     color="black",bbox=dict(facecolor=make_lighter(Color_Max,0.1), edgecolor="black", boxstyle="round,pad=0.3"))
            # الجزء الداخلي (القيمة الأصغر)
            ax.bar(mid_angle, Min, width=end_angle-start_angle, color=Color_Min, edgecolor="black",bottom=Circle_size)
            ax.text(mid_angle,Min , f"{Min:02.0f}%", ha="center", va="center", fontsize=8,fontweight="bold",
                     color="black",bbox=dict(facecolor=make_lighter(Color_Min,0.1), edgecolor="black", boxstyle="round,pad=0.3"))









            # حساب زاوية دوران النص
            rotation_angle = np.degrees(mid_angle) + 90
            if 0 < np.degrees(mid_angle) < 180:
                rotation_angle += 180

            # كتابة الاحصائيات
            ax.text(mid_angle, Metric_distance+Circle_size, auto_split(metrics[i], max_len=12), ha="center", va="center", 
                    fontsize=Metric_size, fontweight="bold", rotation=rotation_angle, rotation_mode="anchor",color=Metric_color)


        # العنوان الرئيسي
        fig.text(0.515, 0.965, First_tittel, size=First_tittel_size, ha="center", color=First_tittel_color)




        # إنشاء الأسطورة
        categories = [
        (player1, Player1_color),
        (player2, Player2_color)]
        legend_handles = [
            plt.Line2D([0], [0], color="none", label=label) for label, _ in categories
        ]

        # عرض الأسطورة في الأعلى بسطر واحد
        legend = fig.legend(
            handles=legend_handles,
            loc='upper center',
            bbox_to_anchor=(0.5, 0.96),
            ncol=len(categories),
            frameon=False,
            fontsize=8
        )

        # تلوين النصوص بنفس لون الفئة  
        for text, (_, color) in zip(legend.get_texts(), categories):
            text.set_color(color)
            text.set_fontweight("bold")
        
        #عرض الرسم
        plt.show()

def Rank(dataset,
          #العنوان الرئيسي للرسم
           First_tittel="Anis",
           First_tittel_color = "#570101",
           First_tittel_size = 12,

           Secend_tittel="",
           Secend_tittel_color = "#570101",
           Secend_tittel_size = 10,
           
           bottom_circle = 10,

           Metric_size = 9,
           Metric_color = "black",
           Metric_distance = 108,
           Metric_color_option = False,

           Max_players = 20,
           ):
    data = pd.DataFrame(dataset)

    #تجهيز قائمة للاعبين بدون تكرار
    selected_players = data["Player"].unique()
    
    if len(selected_players) > 0:
        # اختيار اللاعب الأول من القائمة
        player_name = selected_players[0]

        # تصفية البيانات للاعب المحدد
        player_data = data[data["Player"] == player_name]

        # ترتيب البيانات حسب الصنف
        player_data = player_data.sort_values(by="Category")

        #تخزين البيانات في قوائم منفصلة
        metrics = player_data["Metric"].astype(str).tolist()
        values = player_data["Rank"].tolist()
        colors = player_data["Color"].astype(str).tolist()
        categories = player_data["Category"].astype(str).tolist()

        #حساب عدد الاحصائيات
        N = len(metrics)

        #حساب الزوايا لكل إحصائية
        angles = np.linspace(0, 2*np.pi, N+1)

        #رسم المخطط
        fig, ax = plt.subplots(figsize=(8, 8), subplot_kw=dict(polar=True))

        # إعدادات الشكل
        ax.set_ylim(0, 110)
        ax.set_xticks([])
        ax.set_yticks([20, 40, 60, 80, 100])
        ax.set_yticklabels(["20", "40", "60", "80", "100"], fontsize=0)

        #إخفاء خط الدائرة الخارجية
        ax.spines["polar"].set_visible(False)

        #رسم الدوائر الدخلية للمخطط
        ax.grid(color="gray", linestyle="--", linewidth=0.7, alpha=0.6)

        #إخفاء الدوائر الدخلية للمخطط
        ax.grid(False)

        #رسم الدوائر الخارجية للمخطط
        theta = np.linspace(0, 2*np.pi, 500)
        ax.plot(theta, [100]*500, color="black", linewidth=0)

        #رسم الخطوط بين كل إحصائية
        for angle in angles[:-1]:
            ax.plot([angle, angle], [bottom_circle, 100+bottom_circle],
            color="white", linestyle="-", linewidth=1)

        # رسم الأجزاء الخارجية والداخلية لكل إحصائية
        for i in range(N):
            # حساب الزاوية لكل فئة
            start_angle = angles[i]
            end_angle = angles[i+1]
            mid_angle = (start_angle + end_angle) / 2

            # تحويل القيم إلى أرقام
            val = percent_to_number(values[i])

            # تحديد اللون
            base_color = colors[i]

            # الجزء الخارجي (لون فاتح)
            ax.bar(mid_angle, 100, width=end_angle-start_angle, 
                color=make_lighter(base_color,0.8), edgecolor="white" ,bottom=bottom_circle)
            
            # الجزء الداخلي (القيمة الفعلية)
            new_val = ((Max_players - val + 1) / Max_players) * 100


            ax.bar(mid_angle, new_val, width=end_angle-start_angle, color=base_color, edgecolor="white", bottom=bottom_circle)
            
            # كتابة القيمة
            ax.text(mid_angle, new_val + bottom_circle, f"{val:02.0f}", ha="center", va="center", fontsize=8,fontweight="bold", color="black",bbox=dict(facecolor=make_lighter(base_color,0.25), edgecolor="black", boxstyle="round,pad=0.2"))
        
            # حساب زاوية دوران اسم الاحصائيات
            rotation_angle = np.degrees(mid_angle) + 90
            if 0< np.degrees(mid_angle) < 180:
                rotation_angle += 180

            #تحديد لون اسم الاحصائيات بناءً على الخيار المحدد
            if Metric_color_option == True:
                Metric_color = base_color

            # كتابة الاحصائيات
            ax.text(mid_angle, (Metric_distance +bottom_circle), auto_split(metrics[i], max_len=12), ha="center", va="center", fontsize=Metric_size, fontweight="bold", rotation=rotation_angle, rotation_mode="anchor",color=Metric_color)


        # كتابة العنوان الرئيسي
        fig.text(0.515, 0.965, First_tittel, size=First_tittel_size, ha="center", color=First_tittel_color, fontweight="bold")

        # كتابة العنوان الفرعي
        fig.text(0.515, 0.930, Secend_tittel, size=Secend_tittel_size, ha="center", color=Secend_tittel_color, fontweight="bold")

        # تجهيز قائمة الفئات والألوان لأسطورة المخطط
        categories = list(dict(zip(categories, colors)).items())
        
        # إنشاء عناصر الأسطورة بناءً على الفئات والألوان
        legend_handles = [  plt.Line2D([0], [0], color="none", label=label) for label, _ in categories]

        # عرض الأسطورة
        legend = fig.legend(
            handles=legend_handles,
            loc='upper center',
            bbox_to_anchor=(0.5, 0.96),
            ncol=len(categories),
            frameon=False,
            fontsize=7,
            columnspacing=0
        )

        # ضبط لون النص في الأسطورة ليتناسب مع الألوان المستخدمة
        for text, (_, color) in zip(legend.get_texts(), categories):
            text.set_color(color)

        # عرض المخطط
        plt.show()






    