import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib
import ast

from wikipedia_tools.processor import processor
from wikipedia_tools.utils import properties, utils

import textwrap


# Helpers
def barplot(x, y, data, xlabel="Year", ylabel="Count", hue=None, title="", dodge=True):
    sns.set(font_scale=1)
    plt.style.use("fivethirtyeight")
    palette = (
        [sns.color_palette("PuBuGn_d")[0], sns.color_palette("PuBuGn_d")[-3]]
        if hue
        else [sns.color_palette("PuBuGn_d")[0]]
    )
    fig, axes = plt.subplots(figsize=(7, 5))
    sns.barplot(
        x=x,
        y=y,
        data=data,
        palette=palette,  # sns.color_palette("PuBuGn_d"),#["#9ecae1", "#cccccc"],
        hue=hue,
        dodge=dodge
        # palette=('Blues_d' if hue is not None else None)
    )
    plt.title(title, fontsize=14)
    plt.xlabel(xlabel, fontsize=12)
    plt.ylabel(ylabel, fontsize=12)

    for label in axes.xaxis.get_ticklabels():
        label.set_rotation(60)

    axes.yaxis.set_major_formatter(matplotlib.ticker.StrMethodFormatter("{x:,.0f}"))

    plt.show()


def get_edited_page_count(
    only_popular=False,
    period=properties.DATE_YEAR,
    desc="YEAR",
    plot=True,
    save: bool = False,
):
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )
    dict_ = [
        {"period": period, "article_count": len(set(period_df["title"].unique()))}
        for period, period_df in periodic_df.groupby(["period"])
    ]

    result_df = pd.DataFrame(dict_)
    if plot:
        barplot(
            "period",
            "article_count",
            result_df,
            ylabel="Count of unique Wikipages",
            xlabel=desc.capitalize(),
            title="{}ly Count of Edited/Created Climate Change Wikipedia Pages".format(
                desc.capitalize()
            ),
        )

    if save:
        utils.create_folder(properties.STATS_FOLDER)
        name = "{}ly_count_edited-and-created_wikipages.csv".format(desc.lower())
        result_df.to_csv(f"{properties.STATS_FOLDER}/{name}")
    return result_df


# get_edited_page_count
def get_created_page_count(
    only_popular=False,
    period=properties.DATE_YEAR,
    desc="YEAR",
    plot=True,
    save: bool = False,
):
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )

    articles = []
    result = []
    for period_, df_ in periodic_df.groupby("period"):
        period_articles = df_["title"].unique().tolist()
        count_new_articles = len([x for x in period_articles if x not in articles])
        articles.extend(period_articles)
        if len(articles) == 0:
            print("error")
        row = {"period": period_, "new_article_count": count_new_articles}
        result.append(row)
    result_df = pd.DataFrame(result)
    if plot:
        barplot(
            "period",
            "new_article_count",
            result_df,
            ylabel="Count of Created Wikipages",
            xlabel=desc.capitalize(),
            title="{}ly Count of Created Climate Change Wikipedia Pages".format(
                desc.capitalize()
            ),
        )

    if save:
        utils.create_folder(properties.STATS_FOLDER)
        name = "{}ly_count_created_wikipages.csv".format(desc.lower())
        result_df.to_csv(f"{properties.STATS_FOLDER}/{name}")
    return pd.DataFrame(result)


def get_revisions_over_time(
    only_popular=False,
    period=properties.DATE_YEAR,
    desc="YEAR",
    plot=True,
    save: bool = False,
):
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )

    dict_ = [
        {"period": period_, "revision_count": df_["revision_count"].sum()}
        for period_, df_ in periodic_df.groupby(["period"])
    ]
    result_df = pd.DataFrame(dict_)

    if plot:
        barplot(
            "period",
            "revision_count",
            result_df,
            ylabel="Count of Wikipage Revisions",
            xlabel=desc.capitalize(),
            title="{}ly Count of Wikipedia Revisions".format(desc.capitalize()),
        )
    if save:
        utils.create_folder(properties.STATS_FOLDER)
        name = "{}ly_count_wikipedia_page_revisions.csv".format(desc.lower())
        result_df.to_csv(f"{properties.STATS_FOLDER}/{name}")
    return result_df


def get_words_over_time(
    only_popular=False,
    period=properties.DATE_YEAR,
    desc="YEAR",
    plot=True,
    save: bool = False,
):
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )
    periodic_df.sort_values(by="timestamp", inplace=True)

    pre_period_content_dict = {}
    result_arr = []

    for period_, df_ in periodic_df.groupby(["period"]):
        current_title_content = {
            row["title"]: str(row["content"]) for _, row in df_.iterrows()
        }
        pre_period_content_dict.update(current_title_content)

        period_word_num = {
            "period": period_,
            "word_count": sum(
                [len(v.split()) for _, v in pre_period_content_dict.items()]
            ),
        }
        result_arr.append(period_word_num)

    result_df = pd.DataFrame(result_arr)
    if plot:
        barplot(
            "period",
            "word_count",
            result_df,
            ylabel="Count of Total Words",
            xlabel=desc.capitalize(),
            title="{}ly Wikipedia Page Word Count".format(desc.capitalize()),
        )
    if save:
        utils.create_folder(properties.STATS_FOLDER)
        name = "{}ly_count_wikipedia_page_words.csv".format(desc.lower())
        result_df.to_csv(f"{properties.STATS_FOLDER}/{name}")

    return result_df


def get_users_over_time(
    only_popular=False,
    period=properties.DATE_YEAR,
    desc="YEAR",
    plot=True,
    save: bool = False,
):
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )
    result_arr = []
    over_time_anonymous = []
    over_time_registered = []
    for period_, df_ in periodic_df.groupby(["period"]):
        anonymous = []
        registered = []

        for user_lst_wiki in df_["users"].values.tolist():
            user_lst = ast.literal_eval(user_lst_wiki)

            anonymous.extend([x for x in user_lst if utils.is_ip(x)])
            registered.extend([x for x in user_lst if not utils.is_ip(x)])

        result_arr.append(
            {
                "period": period_,
                "count_edits": len(registered),
                "count_unique_users": len(set(registered)),
                "User Type": "Registered User",
            }
        )
        result_arr.append(
            {
                "period": period_,
                "count_edits": len(anonymous),
                "count_unique_users": len(set(anonymous)),
                "User Type": "Anonymous User",
            }
        )
        over_time_anonymous.extend(anonymous)
        over_time_registered.extend(registered)

    print("Total of Unique Anonymous Users:  ", len(set(over_time_anonymous)))
    print("Total of Unique Registered Users: ", len(set(over_time_registered)))

    result_df = pd.DataFrame(result_arr)
    if plot:
        barplot(
            "period",
            "count_edits",
            result_df,
            ylabel="Count of Revisions",
            xlabel=desc.capitalize(),
            title="{}ly edits count of Wikipedia Pages Per user type".format(
                desc.capitalize()
            ),
            hue="User Type",
            dodge=True,
        )
        barplot(
            "period",
            "count_unique_users",
            result_df,
            ylabel="Count of Unique Users",
            xlabel=desc.capitalize(),
            title="{}ly Count of Wikipedia Page Users".format(desc.capitalize()),
            hue="User Type",
            dodge=True,
        )

    if save:
        utils.create_folder(properties.STATS_FOLDER)
        name = "{}ly_count_wikipedia_page_users.csv".format(desc.lower())
        result_df.to_csv(f"{properties.STATS_FOLDER}/{name}")
    return result_df


def get_most_edited_articles(
    top=3, only_popular=False, period=properties.DATE_YEAR, desc="YEAR", plot=True
):
    sns.set(font_scale=1)
    plt.style.use("fivethirtyeight")
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )
    num_period = len(periodic_df["period"].unique())
    f, axes = plt.subplots(1, num_period, sharex=False, sharey=True, figsize=(20, 6))

    idx = 0
    for period_, df_ in periodic_df.groupby(["period"]):
        top_titles_df = (
            df_[["title", "revision_count"]]
            .groupby("title")
            .sum()
            .sort_values(by="revision_count", ascending=False)
            .reset_index()[0:top]
        )

        ax = axes[idx]
        f.add_subplot(axes[idx])
        sns.barplot(
            x="title",
            y="revision_count",
            data=top_titles_df,
            color=sns.color_palette("PuBuGn_d", num_period)[idx],
        )

        # labels = [textwrap.fill(label.get_text(), 15) for label in ax.get_xticklabels()]
        # ax.set_xticklabels(labels)
        plt.gca().set_xticklabels(
            ax.get_xticklabels(), rotation=90, ha="right", fontsize=10
        )
        plt.gca().set_title(period_, fontsize=14)
        plt.gca().set_xlabel("")
        plt.gca().set_ylabel("")

        idx = idx + 1

    # plt.tight_layout()
    plt.subplots_adjust(wspace=1, hspace=2)
    plt.margins(x=0, y=0)
    # f.text(1, -0.32, 'Year', ha='center')
    f.text(
        0.5,
        1,
        "Top {} Titles per {}".format(top, desc.capitalize()),
        ha="center",
        fontsize=16,
    )
    plt.show()


def get_periodic_most_to_least_revised(
    only_popular=False, period=properties.DATE_YEAR, desc="YEAR", save: bool = False
):
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )
    num_period = len(periodic_df["period"].unique())

    _dict = {}
    for period_, df_ in periodic_df.groupby(["period"]):
        sorted_titles = (
            df_[["title", "revision_count"]]
            .groupby("title")
            .sum()
            .sort_values(by="revision_count", ascending=False)
            .reset_index()
        )
        _dict[period_] = sorted_titles["title"].values.tolist()

    max = -1
    for _, v in _dict.items():
        max = len(v) if max < len(v) else max
    extended_dict = {k: v + ([""] * (max - len(v))) for k, v in _dict.items()}

    result_df = pd.DataFrame(extended_dict)
    if save:
        utils.create_folder(properties.STATS_FOLDER)
        name = "{}ly_most-to-least_revised_wikipedia_pages.csv".format(desc.lower())
        result_df.to_csv(f"{properties.STATS_FOLDER}/{name}")
    return result_df


def get_attr_for_period_as_txt(
    period_val,
    attr_val: str = "links",
    only_popular=False,
    period=properties.DATE_YEAR,
    desc="YEAR",
) -> []:  ## could be categories or urls
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )
    periodic_df = periodic_df[periodic_df["period"] == period_val].copy()
    periodic_df.sort_values(
        by=["revision_count", "title"], inplace=True, ascending=False
    )

    result_arr = []
    for _, row in periodic_df.iterrows():
        lst_ = ast.literal_eval(row[attr_val])
        lst_ = [x.replace(" ", "") for x in lst_]
        if len(lst_) > 0:
            result_arr.append(". ".join(lst_))

    utils.create_folder(properties.STATS_FOLDER)
    with open(
        f"{properties.STATS_FOLDER}/{attr_val}_{period_val}.txt", "w", encoding="utf-8"
    ) as f:
        for line in result_arr:
            f.write(f"{line}\n")
    return result_arr


def get_periodic_revisions_percentage(
    only_popular=False, period=properties.DATE_YEAR, desc="YEAR", save: bool = False
):
    periodic_df = processor.get_wikipedia_page_periodic_overview(
        only_popular=only_popular, period=period, desc=desc
    )
    periodic_df.sort_values(
        by=["period", "revision_count", "title"], inplace=True, ascending=False
    )

    periodic_df["revision_percentage"] = round(
        100
        * periodic_df["revision_count"]
        / periodic_df.groupby("period")["revision_count"].transform("sum"),
        3,
    )
    result_df = periodic_df[
        ["period", "title", "revision_count", "revision_percentage", "timestamp"]
    ]
    if save:
        utils.create_folder(properties.STATS_FOLDER)
        name = "{}ly_wikipedia_page_revisions_w_percentage.csv".format(desc.lower())
        result_df.to_csv(f"{properties.STATS_FOLDER}/{name}")

    return result_df
