import seaborn as sns
import matplotlib as mpl
from matplotlib import pyplot as plt
PALETTE = 10 * (
    "#377eb8",
    "#4daf4a",
    "#984ea3",
    "#e41a1c",
    "#ff7f00",
    "#a65628",
    "#f781bf",
    "#888888",
    "#a6cee3",
    "#b2df8a",
    "#cab2d6",
    "#fb9a99",
    "#fdbf6f",
)


def plot(filepath, ext='png'):
    """
    Saves the current plot to a file and displays it.

    :param filepath: The path to save the plot file.
    :type filepath: str
    :param ext: The file extension of the saved plot. Default is 'png'.
    :type ext: str
    """
    plt.tight_layout()
    figure = plt.gcf()
    ax = plt.gca()
    legends = [c for c in ax.get_children() if isinstance(c, mpl.legend.Legend)]

    if legends:
        figure.savefig(str(filepath), format=ext,  bbox_extra_artists=(*legends,), bbox_inches='tight')
    else:
        figure.savefig(str(filepath), format=ext)

    plt.show()
    plt.clf()


def prepare_tex(df, hue, style, hue_order):
    """
    Prepares a line plot for rendering in LaTeX.

    :param df: The DataFrame containing the data to be plotted.
    :type df: pandas.DataFrame
    :param hue: Grouping variable that will produce lines with different colors.
    :type hue: str
    :param style: Grouping variable that will produce lines with different styles.
    :type style: str
    :param hue_order: Order for the levels of the hue variable in the plot.
    :type hue_order: list
    :return: The prepared line plot.
    :rtype: matplotlib.axes._subplots.AxesSubplot
    """
    sns.set(rc={'text.usetex': True}, style='whitegrid')
    lineplot = sns.lineplot(data=df, x='Episode', y='Score', ci=95, palette=PALETTE,
                            hue_order=hue_order, hue=hue, style=style)
    lineplot.set_title(f'{sorted(list(df["Measurement"].unique()))}')
    plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', borderaxespad=0)
    plt.tight_layout()
    return lineplot


def prepare_plt(df, hue, style, hue_order):
    """
    Prepares a line plot using matplotlib.

    :param df: The DataFrame containing the data to be plotted.
    :type df: pandas.DataFrame
    :param hue: Grouping variable that will produce lines with different colors.
    :type hue: str
    :param style: Grouping variable that will produce lines with different styles.
    :type style: str
    :param hue_order: Order for the levels of the hue variable in the plot.
    :type hue_order: list
    :return: The prepared line plot.
    :rtype: matplotlib.axes._subplots.AxesSubplot
    """
    print('Struggling to plot Figure using LaTeX - going back to normal.')
    plt.close('all')
    sns.set(rc={'text.usetex': False}, style='whitegrid')
    lineplot = sns.lineplot(data=df, x='Episode', y='Score', hue=hue, style=style,
                            errorbar=('ci', 95), palette=PALETTE, hue_order=hue_order, )
    plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', borderaxespad=0)
    plt.tight_layout()
    # lineplot.set_title(f'{sorted(list(df["Measurement"].unique()))}')
    return lineplot


def prepare_center_double_column_legend(df, hue, style, hue_order):
    """
    Prepares a line plot with a legend centered at the bottom and spread across two columns.

    :param df: The DataFrame containing the data to be plotted.
    :type df: pandas.DataFrame
    :param hue: Grouping variable that will produce lines with different colors.
    :type hue: str
    :param style: Grouping variable that will produce lines with different styles.
    :type style: str
    :param hue_order: Order for the levels of the hue variable in the plot.
    :type hue_order: list
    :return: The prepared line plot.
    :rtype: matplotlib.axes._subplots.AxesSubplot
    """
    print('Struggling to plot Figure using LaTeX - going back to normal.')
    plt.close('all')
    sns.set(rc={'text.usetex': False}, style='whitegrid')
    _ = plt.figure(figsize=(10, 11))
    lineplot = sns.lineplot(data=df, x='Episode', y='Score', hue=hue, style=style,
                            ci=95, palette=PALETTE, hue_order=hue_order, legend=False)
    # plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', borderaxespad=0)
    lineplot.legend(hue_order, ncol=3, loc='lower center', title='Parameter Combinations', bbox_to_anchor=(0.5, -0.43))
    plt.tight_layout()
    return lineplot


def prepare_plot(filepath, results_df, ext='png', hue='Measurement', style=None, use_tex=False):
    """
    Prepares a line plot for visualization. Based on the use tex parameter calls the prepare_tex or prepare_plot
    function accordingly, followed by the plot function to save the plot.

    :param filepath: The file path where the plot will be saved.
    :type filepath: str
    :param results_df: The DataFrame containing the data to be plotted.
    :type results_df: pandas.DataFrame
    :param ext: The file extension of the saved plot (default is 'png').
    :type ext: str
    :param hue: The variable to determine the color of the lines in the plot.
    :type hue: str
    :param style: The variable to determine the style of the lines in the plot (default is None).
    :type style: str or None
    :param use_tex: Whether to use LaTeX for text rendering (default is False).
    :type use_tex: bool
    """
    df = results_df.copy()
    df[hue] = df[hue].str.replace('_', '-')
    hue_order = sorted(list(df[hue].unique()))
    if use_tex:
        try:
            _ = prepare_tex(df, hue, style, hue_order)
            plot(filepath, ext=ext)  # plot raises errors not lineplot!
        except (FileNotFoundError, RuntimeError):
            _ = prepare_plt(df, hue, style, hue_order)
            plot(filepath, ext=ext)
    else:
        _ = prepare_plt(df, hue, style, hue_order)
        plot(filepath, ext=ext)