########## LIBRARIES ##########
import streamlit as st
import pandas as pd
import numpy as np
import plotly.graph_objects as go
from streamlit_searchbox import st_searchbox
from module.__selectpage__ import st_page_selectbox

########## DATASET ##########
df = pd.read_csv('./data/join_02.csv')
df['date'] = pd.to_datetime(df['date'])                 # Format preparation
df['release_date'] = pd.to_datetime(df['release_date'])
df['avg_peak_perc'] = df['avg_peak_perc'].str.rstrip('%').astype('float') 
df = df.dropna()


########## FUNCTION ##########
##### Adding single-player feature
def add_opp_features(genre):
    df[genre[0]] = (df[genre[1]]==0)*1

##### Adding feature depending on range of a base feature
"""Scenario of using this function
For example, if we want a feature of price
between $10 to $30
"""
def add_range_features(arg):
    lower = arg[0]; upper = arg[1]
    name = arg[2]; genre = arg[3]
    
    condition = (df[genre]>=lower) & (df[genre]<upper)
    df[name] = condition*1

# Returning title version of feature name
def name(target):
    return target.replace('_', ' ').title()

##### Searchbox Functions
# Appending favorite game selected by user to filtered list
    """use after search box
    """
def add_top_games(top_games, fav_games, ranges, df_ax):
    ranges_last = ranges[1]
    for fav in fav_games:
        if fav in top_games: 
            range_last+=1
            top_games = df_ax.gamename.unique()[ranges[0]-1:range_last]
        elif fav!=None: 
            top_games = np.append(top_games, fav)
    return top_games

def add_list(favorite_game, rec_games):
    fav_games = []
    if favorite_game[0]: fav_games = favorite_game
    if rec_games: 
        fav_games = list(set(fav_games + rec_games))
    return fav_games

# fav_games = []
# if favorite_game: fav_games = [favorite_game]
# if st.session_state.gamenames[-1]: 
#     rec_games = st.session_state.gamenames[-1]
#     fav_games = list(set(fav_games + rec_games))

# def add_top_games(top_games, favorite_game, ranges, df_ax):
#     if favorite_game in top_games: 
#         top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]+1]
#     elif favorite_game!=None: 
#         top_games = np.append(top_games, favorite_game)
#     return top_games

# Linear search over all gamenames
def search(target):
    gamenames = df['gamename'].unique()                 # all unique gamenames
    result = []
    for gamename in gamenames:
        if target.lower() in gamename.lower():          # games that contains the searching keyword
            result.append(gamename)
    return result 

# Streamlit search box
def searchbox():
    selected_game = st_searchbox(
        search_function=search,
        key="gamename_searchbox",
        default_options=None, 
        placeholder="Compare with your Favorite Game...",
    )
    return selected_game

# Overloaded with target name 
def searchbox(target):
    col1, col2= st.columns([1,1])
    with col1:  
        selected_game = st_searchbox(
            search_function=search,
            key="gamename_searchbox",
            default_options=target, 
            placeholder="Compare with your Favorite Game...",
        )
    return selected_game

########## PAGE SECTION ##########
# Datafram Section
    """Dataframe
    together with Title
    """
def dfbox(ax_name, y_name, df_ax, ranges, order_name):
    title = f"1.2 :blue[{ax_name}] Games with the {order_name} :blue[{y_name}]:"
    with st.sidebar:
        gamenames = df_ax.gamename.unique()
        df_names = pd.DataFrame(gamenames, columns=['gamename'])
        st.write(title)
        st.dataframe(df_names[ranges[0]:ranges[1]+1])

def rec_dfbox():
    title = f"1.1 :blue[Recommended] by :green[GameInsightify]"
    if len(st.session_state.gamenames) > 0:
        with st.sidebar:
            rec_games = st.session_state.gamenames[-1]
            df_names = pd.DataFrame(rec_games, columns=['gamename'])
            st.write(title)
            st.dataframe(df_names[0:len(rec_games)])
# Overloaded with argument of names
def home_dfbox(rec_games):
    title = f":blue[Recommended] by :green[GameInsightify]"
    if len(rec_games) > 0:
        with st.sidebar:
            df_names = pd.DataFrame(rec_games, columns=['gamename'])
            st.write(title)
            st.dataframe(df_names[0:len(rec_games)])


# plot 1 Section
    """Plot contains the top ranked games
    based on the selected features, 
    within selected genre
    """
def plot1_box(ax, y, order_name, ranges, df_ax, top_games):
    ax_name = name(ax)          # formating strings
    y_name = name(y)            # formeting strings
    
    title = f"1.3 Rank {ranges[0]} to {ranges[1]} :blue[{ax_name}] Games with the :red[{order_name}] :blue[{y_name}]"
    st.subheader(title)

    # Plot 1 - select box
    rec_games = []
    if len(st.session_state.gamenames) > 0 : rec_games = st.session_state.gamenames[-1]
    favorite_game = searchbox(None)                                                     # search box to add a user favorite game on Plot 1
    fav_games = add_list([favorite_game], rec_games)
    fav_options = st.multiselect('Select Recommended Games', fav_games)
    
    options = top_games
    selected_tops = st.multiselect('Select Video Games', options)
    selected_options = add_top_games(selected_tops, fav_options, ranges, df_ax) 

    # Plot 1
    title_names = ','.join(selected_options)
    plot_title = f"Monthly {y_name} of {title_names} Over Time"
    gb = df.sort_values(by='date')
    gb_list = {game: gb[gb["gamename"] == game] for game in selected_options}

    fig_1 = go.Figure()
    fig_1.update_layout(
        title = plot_title, 
        xaxis_title = 'Date',
        yaxis_title = y_name,
    )
    for game, gb in gb_list.items():
        fig_1 = fig_1.add_trace(go.Scatter(x=gb["date"], y=gb[y], name=game, mode='lines'))
    st.plotly_chart(fig_1)

def plot2_box(theme, y, genres, df_bx):
    y_name = name(y)
    
    title = f"2.0 Comparison Among :blue[{theme}] on Monthly :blue[{y_name}]:"
    st.subheader(title)

    # Plot 2 - Multiselect box
    options = genres
    selected_options = st.multiselect('Select Comparing Categories', options)
    selected_names = ','.join(selected_options)                         # formating titles
    plot_title = f"Monthly {y_name} of {selected_names} Over Time"


    # Plot 2

    # Tab 1 - Mean Line Plot
    gb = df_bx.sort_values(by='date')      # New copy of df
    mean_list = {genre: gb[gb[genre] == 1].groupby('date').mean(y).reset_index() for genre in selected_options}

    fig_mean = go.Figure()
    for genre, gb in mean_list.items():
        fig_mean = fig_mean.add_trace(go.Scatter(x=gb['date'], y=gb[y], name=genre, mode='lines'))
    fig_mean.update_layout(
        title = 'Mean of ' + plot_title,
        xaxis_title = 'Date',
        yaxis_title = 'Mean of '+y_name,
    )


    # Tab 2 - Sum Line Plot
    gb = df_bx.sort_values(by='date')
    sum_list = {genre: gb[gb[genre] == 1].groupby('date').sum(y).reset_index() for genre in selected_options}

    fig_sum = go.Figure()
    for genre, gb in sum_list.items():
        fig_sum = fig_sum.add_trace(go.Scatter(x=gb['date'], y=gb[y], name=genre))
    fig_sum.update_layout(
        title = 'Sum of ' + plot_title,
        xaxis_title='Date',
        yaxis_title='Sum of '+y_name,
    )

    # Tab 3 - Scatter / Marker Plot
    gb = df_bx.sort_values(by='date')
    gb_list = {genre: gb[gb[genre] == 1] for genre in selected_options}

    fig_sc = go.Figure()
    for genre, gb in gb_list.items():
        fig_sc = fig_sc.add_trace(go.Scatter(x=gb["date"], y=gb[y], name=genre, mode='markers'))
    fig_sc.update_traces(
        marker=dict(size=4, opacity=0.5)
    )
    fig_sc.update_layout(
        title = plot_title,
        xaxis_title='Date',
        yaxis_title=y_name,
    )


    # Showing Plot
    tab1, tab2, tab3 = st.tabs(['Line Plot', 'Sum Plot', 'Scatter Plot'])
    with tab1:
        st.plotly_chart(fig_mean)
    with tab2:
        st.plotly_chart(fig_sum)
    with tab3:
        st.plotly_chart(fig_sc)

# Plot 3 - Pie chart
import plotly.express as px
def plot3_box(theme, labels):
    title = f"2.1 Ratio of Games Among :blue[{theme}]"
    st.subheader(title)
    
    if (type(labels)==str):
        values = []
        index = df[labels].unique().tolist()
        for idx, value in enumerate(index):
            count = len(df[df[labels] == value])
            values.append(count)
            if(count/len(df) < 0.02): index[idx] = 'Other'
        
        df_p = pd.DataFrame(data = values,  
                index = index,  
                columns = ['counts']) 
        df_p = df_p.reset_index().rename(columns={'index':labels})
        fig_ratio = px.pie(df_p, values='counts', names=labels)
        st.plotly_chart(fig_ratio)
        
    else:
        values = []
        for label in labels:
            value = len(df[df[label]==1])
            values.append(value)
        
        fig_ratio = go.Figure(data=[go.Pie(labels=labels, values=values)])
        st.plotly_chart(fig_ratio)

# Could not overload function, so renamed it
def plot3_box_limit(theme, labels, limit_perc):
    title = f"2.1 Ratio of Games Among :blue[{theme}] over :blue[{limit_perc*100}%]"
    st.subheader(title)
    
    values = []
    index = df[labels].unique().tolist()
    for idx, value in enumerate(index):
        count = len(df[df[labels] == value])
        values.append(count)
        if(count/len(df) < limit_perc): index[idx] = 'Other'
    
    df_p = pd.DataFrame(data = values,  
            index = index,  
            columns = ['counts']) 
    df_p = df_p.reset_index().rename(columns={'index':labels})
    fig_ratio = px.pie(df_p, values='counts', names=labels)
    st.plotly_chart(fig_ratio)

def plot_chat_box(y, query_num, top_games):
    y_name = name(y)            # formeting strings
    
    title = f"1.2 Comparison on The {query_num} Best Recommended Games on :blue[{y_name}]"
    st.subheader(title)

    # Plot 1 - select box                                                    # search box to add a user favorite game on Plot 1
    options = top_games
    selected_options = st.multiselect('Select Video Games', options)

    # Plot 1
    title_names = ','.join(selected_options)
    plot_title = f"Monthly {y_name} of {title_names} Over Time"
    gb = df.sort_values(by='date')
    gb_list = {game: gb[gb["gamename"] == game] for game in selected_options}

    fig_1 = go.Figure()
    fig_1.update_layout(
        title = plot_title, 
        xaxis_title = 'Date',
        yaxis_title = y_name,
    )
    for game, gb in gb_list.items():
        fig_1 = fig_1.add_trace(go.Scatter(x=gb["date"], y=gb[y], name=game, mode='lines'))
    st.plotly_chart(fig_1)


##### Execute Page #####
def exec_page(emoji, theme, page_genres):
    # Select Page
    st_page_selectbox(theme)
    
    # Header
    st.header(emoji)
    st.header(f"Customized Plot on :blue[{theme}]")

    ##### FILTER #####
    # Featuer for both axis
    features = ['avg', 'gain', 'peak', 'avg_peak_perc']
    features += ['metacritic_score', 'positive', 'negative']
    genres = page_genres
    ##################


    # User Menu
    order = st.toggle(label='Rank the Worst Games', value=False)                    # descending order toggle switch
    left_col, right_col = st.columns(2)                                             # Columns dividing 
    with left_col: y = st.selectbox("Select a Feature (y-axis)", features)          # feature select box (y axis of Plots)
    with right_col: ax = st.selectbox("Select a Genre (legend)", genres)            # category select box (filtering game basse on genre)

    order_name='Worst' if order else 'Highest'                                      # string formating
    y_name = name(y)                                            # string of names that would be used on Plot title
    ax_name = name(ax)

    # Data - sorting and filtering
    df_ax = df[df[ax]==1]
    df_ax = df_ax[['gamename', 'date', y, ax]].sort_values(by=y, ascending=order).reset_index()     # Data for Plot 1
    df_bx = df[['gamename', 'date', y]+genres].sort_values(by=y, ascending=order).reset_index()     # Data for Plot 2


    # Slider
    max = df_ax.gamename.unique().tolist()                          # max number of games
    max = len(max)-1
    ranges = st.slider(
        label=f'Select range of the {order_name.lower()} games',
        value = (1, 3), 
        min_value=1, max_value=30, 
        # min_value=1, max_value=max, 
    )
    top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]]
    

    # Dataframe preview
    rec_dfbox()
    dfbox(ax_name, y_name, df_ax, ranges, order_name)  

    ##### PLOT 1 #####
    # Plot 1 - markdown
    st.markdown("""***""")
    plot1_box(ax, y, order_name, ranges, df_ax, top_games)

    ##### PLOT 2 #####
    # Plot 2 - markdown
    st.markdown("""***""")
    plot2_box(theme, y, genres, df_bx)

##### HOME PAGE #####
def exec_page_home(theme):
    st_page_selectbox(theme)
    
    # Header
    st.header("👋")
    st.header("Customized Plot on :blue[General Features]")

    ##### FILTER #####
    # Featuer for both axis
    features = ['avg', 'gain', 'peak', 'avg_peak_perc']
    genres = features


    left_col, right_col = st.columns(2)
    order = st.toggle(label='Rank the Worst Games', value=False)        # descending order toggle switch
    y = st.selectbox("Select a Feature (y-axis)", features)                      # feature select box
    order_name='Worst' if order else 'Highest'                          # string formating
    y_name = name(y)

    # Data - sorting and filtering
    df_ax = df[['gamename', 'date', y]].sort_values(by=y, ascending=order).reset_index()    # Data - Plot 1
    # df_bx = df[['gamename', 'date']+features].sort_values(by=y, ascending=order).reset_index()      # Data - Plot 2

    # Slider
    max = df_ax.gamename.unique().tolist()
    max = len(max)-1
    ranges = st.slider(
        label=f'Select range of the {order_name.lower()} games',
        value = (1, 3),
        min_value=1, max_value=30, 
        # min_value=1, max_value=max, 
    )
    top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]]

    # Dataframe preview
    rec_dfbox()
    dfbox("", y_name, df_ax, ranges, order_name)


    ##### PLOT 1 #####
    # Plot 1 - markdown
    st.markdown("""***""")
    title = f"1.3 Rank {ranges[0]} to {ranges[1]} Games with the Overall :red[{order_name}] :blue[{y_name}]"
    st.subheader(title)


    # Plot 1 - select box
    rec_games = []
    if len(st.session_state.gamenames)>0: rec_games = st.session_state.gamenames[-1]
    favorite_game = searchbox(None)                                                     # search box to add a user favorite game on Plot 1
    fav_games = add_list([favorite_game], rec_games)
    fav_options = st.multiselect('Select Recommended Games', fav_games)
    
    options = top_games
    selected_tops = st.multiselect('Select Video Games', options)
    selected_options = add_top_games(selected_tops, fav_options, ranges, df_ax) 

    # Plot 1
    title_names = ','.join(selected_options)
    plot_title = f"Monthly {y_name} of {title_names} Over Time"
    gb = df_ax.sort_values(by='date')
    gb_list = {game: gb[gb["gamename"] == game] for game in selected_options}

    fig_1 = go.Figure()
    fig_1.update_layout(
        title = plot_title, 
        xaxis_title = 'Date',
        yaxis_title = y_name,
    )
    for game, gb in gb_list.items():
        fig_1 = fig_1.add_trace(go.Scatter(x=gb["date"], y=gb[y], name=game, mode='lines'))
    st.plotly_chart(fig_1)

##### PUBLISHERS PAGE #####
def exec_page_pub(emoji, theme, main_genre):
    st_page_selectbox(theme)
    
    # Header
    st.header(emoji)
    st.header(f"Customized Plot on :blue[{theme}]")

    ##### FILTER #####
    # Featuer for both axis
    features = ['avg', 'gain', 'peak', 'avg_peak_perc']
    features += ['metacritic_score', 'positive', 'negative']
    genres = []

    left_col, right_col = st.columns(2)
    order = st.toggle(label='Find the Worst Games', value=False)        # descending order toggle switch
    with left_col: 
        y = st.selectbox("Select a Feature", features)                  # feature select box
    with right_col: 
        if (main_genre=='publishers'):
            genres = df.sort_values(by=y, ascending=order).publishers.unique()[0:5].tolist()
        elif (main_genre=='developers'):
            genres = df.sort_values(by=y, ascending=order).developers.unique()[0:5].tolist()
        
        for genre in genres:
            df[genre] = (df[main_genre]==genre)*1
        ax = st.selectbox("Select a Category", genres)                  # category select box
    order_name='Worst' if order else 'Highest'                          # string formating
    y_name = y.replace('_', ' ').title()
    ax_name = ax.title().replace('_', ' ')

    # ### adding best publisher features feature ###

    # Data - sorting and filtering
    df_ax = df[df[ax]==1]
    df_ax = df_ax[['gamename', 'date', y, ax]].sort_values(by=y, ascending=order).reset_index()    # Data - Plot 1
    df_bx = df[['gamename', 'date', y]+genres].sort_values(by=y, ascending=order).reset_index()      # Data - Plot 2

    # Slider
    max = df_ax.gamename.unique().tolist()
    max = len(max)
    if(max < 2):value_r = 0
    elif(max > 4):value_r = 5
    else: value_r = max

    ranges = st.slider(
        label=f'Select range of the {order_name.lower()} games',
        value = (1, value_r),
        # min_value=0, max_value=30, 
        min_value=1, max_value=max, 
    )
    top_games = df_ax.gamename.unique()[ranges[0]-1:ranges[1]]

    # Dataframe preview
    rec_dfbox()
    dfbox(ax_name, y_name, df_ax, ranges, order_name)

    title = f"1.2 5 :blue[{theme}s] with the :red[{order_name}] Monthly :blue[{y_name}]:"
    st.subheader(title)
    st.dataframe(genres[0:5])



    ##### PLOT 1 #####
    # Plot 1 - markdown
    st.markdown("""***""")
    plot1_box(ax, y, order_name, ranges, df_ax, top_games)


    ##### PLOT 2 #####
    # Plot 2 - markdown
    st.markdown("""***""")
    plot2_box(theme, y, genres, df_bx)