import dash
from dash import dcc, html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import pandas as pd
import plotly.express as px
from datetime import datetime, timedelta
import itertools 
from PIL import Image

# Use the Dash Bootstrap Components theme
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

# Load the initial data from the dice_roll_data.csv file into a Pandas DataFrame
df = pd.read_csv('dice_roll_data.csv')

# Calculate initial statistics
result_counts = df['roll'].value_counts().sort_index()
total_rolls = result_counts.sum()
# Assuming df is the DataFrame containing the rolls
current_roll = df['roll'].iloc[-1] if not df.empty else 0  # Default to 0 if the DataFrame is empty
# Count consecutive occurrences of the current roll value
consecutive_count = sum(1 for _ in itertools.takewhile(lambda x: x == current_roll, reversed(df['roll'])))
# Initial health value, adjust as needed
progress_value = 2000
max_progress_value = 2000
max_damage = 0

# Create initial figure with px.bar
fig = px.bar(y=result_counts.index, x=result_counts.values, labels={'x': 'Count', 'y': 'Result'}, orientation='h')

# Update layout for the bar chart to make the axis titles and tick labels larger
fig.update_xaxes(tickfont=dict(size=24), title_font=dict(size=28))
fig.update_yaxes(tickfont=dict(size=24), title_font=dict(size=28))

# Add title to the bar chart
# fig.update_layout(title_text="Allo", title_font=dict(size=32), title_x=0.5)

# Calculate the end time for the countdown timer (December 2, 2023, at 3:30 pm)
end_time = datetime(2023, 12, 2, 15, 30, 0)

# Function to find the maximal consecutive occurrence of a given roll value
def find_max_consecutive_occurrence(series, roll_value):
    max_consecutive_occurrence = 0
    current_consecutive_occurrence = 0

    for i in range(1, len(series)):
        if series.iloc[i] == roll_value and series.iloc[i - 1] == roll_value and (series.index[i] - series.index[i - 1]) == 1:
            current_consecutive_occurrence += 1
        elif series.iloc[i] == roll_value:
            current_consecutive_occurrence = 1
        else:
            current_consecutive_occurrence = 0

        max_consecutive_occurrence = max(max_consecutive_occurrence, current_consecutive_occurrence)

    return max_consecutive_occurrence

def calculate_cumulative_damage(rolls):
    cumulative_damage = []
    current_value = None
    consecutive_count = 0

    for roll in rolls:
        if roll == current_value:
            consecutive_count += 1
        else:
            consecutive_count = 1
            current_value = roll

        damage = roll * (2 ** (consecutive_count - 1))
        cumulative_damage.append(damage)

    return cumulative_damage


# Function to read values from the info.txt file
def read_info_file():
    try:
        with open('info.txt', 'r') as file:
            lines = file.readlines()
            if lines:
                values = lines[0].strip().split(',')
                if len(values) == 3:
                    inference_rate, latency, power_consumption = map(float, values)
                    return inference_rate, latency, power_consumption
    except Exception as e:
        print(f"Error reading info.txt: {e}")
    return None, None, None

# Calculate the maximal consecutive occurrence for each roll
max_consecutive_occurrences = {roll: find_max_consecutive_occurrence(df['roll'], roll) for roll in range(1, 7)}


# Define layout using Dash components and Dash Bootstrap Components
app.layout = dbc.Container(
    fluid=True,
    children=[
        # Row 1: Cells 1 and 2
        dbc.Row([
            dbc.Col(
                dbc.Card(
                    dbc.CardBody(
                        [
                            html.Img(src=dash.get_asset_url('oogie.gif'), alt='Oogie Boogie', className='img-fluid mx-auto my-auto', style={'width': '75%', 'max-height': '100%', 'border-radius': '25px'}),
                            dbc.Progress(
                                id='progress-bar',
                                value=progress_value,
                                color="success",
                                max=max_progress_value,
                                style={'margin-top': '20px', 'height': '30px', 'background-color': 'red'},
                            ),
                            html.P(f'Health: {progress_value:.0f}/{max_progress_value}', id='health-text', className='lead text-center fw-bold', style={'font-size': '24px', 'margin-top': '10px'}),
                        ],
                        className='text-center'
                    ),
                    className='border p-3',
                    style={'height': '100%'}
                ),
                width=6
            ),
            dbc.Col(
                # Cell 2: Countdown, System infos, and Table with max consecutive occurrences for each roll
                dbc.Card(
                    [   
                        dcc.Interval(
                            id='interval-component',
                            interval=1*1000,  # in milliseconds
                            n_intervals=0
                        ),
                        html.P(id='countdown-timer', className='lead text-center fw-bold', style={'font-size': '32px'}),
                        dbc.CardBody(
                            [
                                # Add new text and values from info.txt
                                html.Div(
                                    [
                                        html.P(id='inference-rate-text', className='lead text-center fw-bold', style={'font-size': '24px', 'margin-right': '10px'}),
                                        html.P(id='latency-text', className='lead text-center fw-bold', style={'font-size': '24px', 'margin-right': '10px'}),
                                        html.P(id='power-consumption-text', className='lead text-center fw-bold', style={'font-size': '24px'}),
                                    ],
                                    style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center', 'margin-top': '20px'},
                                ),
                                
                                html.Div(
                                    [
                                        html.Img(src=dash.get_asset_url('dice-pc.png'), alt='Actuel', className='img-fluid mx-auto my-auto', style={'width': '50%', 'max-height': '100%', 'border-radius': '25px'}),
                                    ],
                                    style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center'},
                                ),
                                html.Div(
                                    [
                                        html.Img(src=dash.get_asset_url('dice-fpga.png'), alt='Cible', className='img-fluid mx-auto my-auto', style={'width': '60%', 'max-height': '100%', 'border-radius': '25px'}),
                                    ],
                                    style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center', 'margin-top': '20px'},
                                ),
                                # html.Img(src=dash.get_asset_url('dice-pc.png'), alt='Actuel', className='img-fluid mx-auto my-auto', style={'width': '55%', 'max-height': '100%', 'border-radius': '25px'}),
                                # html.Img(src=dash.get_asset_url('dice-fpga.png'), alt='Cible', className='img-fluid mx-auto my-auto', style={'width': '5%', 'max-height': '100%', 'border-radius': '25px'}),
                                # dbc.Table(
                                #     id='max-consecutive-occurrence-table',
                                #     children=[
                                #         html.Thead(
                                #             html.Tr([html.Th('Roll', style={'font-size': '28px'}), html.Th('Max Consecutive Occurrence', style={'font-size': '28px'})])
                                #         ),
                                #         html.Tbody(
                                #             [html.Tr([html.Td(f'{roll}', style={'font-size': '24px'}), html.Td(f'{max_consecutive_occurrences[roll]}', style={'font-size': '24px'})]) for roll in range(1, 7)]
                                #         )
                                #     ],
                                #     className='text-center',
                                #     style={'margin-top': '20px'}
                                # ),
                            ],
                            className='text-center'
                        ),
                    ],
                    className='border p-3',
                    style={'height': '100%'}
                ),
                width=6
            )
        ], align='stretch', style={'margin-bottom': '20px'}),

        # Row 2: Cells 3 and 4
        dbc.Row([
            dbc.Col(
                # Cell 3
                dbc.Card(
                    dbc.CardBody(
                        [
                            html.Div(
                                [
                                    html.Div(
                                        [
                                            html.H5("Previous Roll", className="card-title fw-bold", style={'margin-bottom': '10px', 'font-size': '32px'}),
                                            html.Img(id='previous-roll-image', alt='previous roll image', className='img-fluid mx-auto my-auto', style={'width': '70%', 'max-height': '100%', 'border-radius': '15px'}),
                                        ],
                                        style={'padding-bottom': '20px', 'padding-right': '75px'}
                                    ),

                                    html.Div(
                                        [
                                            html.H5("Current Roll", className="card-title fw-bold", style={'margin-bottom': '10px', 'font-size': '32px'}),
                                            html.Img(id='current-roll-image', alt='current roll image', className='img-fluid mx-auto my-auto', style={'width': '70%', 'max-height': '100%', 'border-radius': '15px'}),
                                        ],
                                        style={'padding-bottom': '20px'}
                                    ),
                                ],
                                style={'display': 'flex', 'justify-content': 'center', 'margin-top': '75px'}
                            ),

                            html.P(id='consecutive-count-text', className='lead text-center fw-bold', style={'font-size': '24px'}),
                            html.P(id='damage-dealt-text', className='lead text-center fw-bold', style={'font-size': '24px'}),
                            html.P(id='max-damage-text', className='lead text-center fw-bold', style={'font-size': '24px'}),

                        ],
                        className='text-center'
                    ),
                    className='border p-3',
                    style={'height': '100%'}
                ),
                width=6
            ),
            dbc.Col(
                # Cell 4: Bar Chart and Probability Table
                dbc.Card(
                    [
                        dbc.CardBody(
                            [
                                html.P(id='total-rolls-text', className='lead text-center fw-bold', style={'font-size': '32px'}),
                                html.Div(
                                    [
                                        # Bar Chart
                                        dcc.Graph(
                                            id='bar-chart',
                                            figure=fig,
                                            style={'height': '80%', 'width': '70%', 'display': 'inline-block'}
                                        ),
                                        # Probability Table
                                        dbc.Table(
                                            id='probability-table',
                                            style={'margin-top': '20px', 'width': '30%', 'display': 'inline-block'},
                                        ),
                                    ],
                                    style={'width': '100%', 'display': 'flex', 'justify-content': 'space-between'}
                                ),
                            ],
                            className='text-center'
                        ),
                    ],
                    # Cell 4
                    className='border p-3',
                    style={'height': '100%'}
                ),
                width=6
            )
        ], align='stretch')
    ]
)


# Callback to update countdown timer text
@app.callback(Output('countdown-timer', 'children'),
              [Input('interval-component', 'n_intervals')])
def update_timer(n_intervals):
    time_left = end_time - datetime.now()
    days, seconds = divmod(time_left.total_seconds(), 86400)
    hours, remainder = divmod(seconds, 3600)
    minutes, seconds = divmod(remainder, 60)

    # Format components with leading zeros
    formatted_hours = str(int(hours)).zfill(2)
    formatted_minutes = str(int(minutes)).zfill(2)
    formatted_seconds = str(int(seconds)).zfill(2)

    return f'Temps restant: {formatted_hours}:{formatted_minutes}:{formatted_seconds}'


# Callback to update data every second
@app.callback([Output('bar-chart', 'figure'),
               Output('total-rolls-text', 'children'),
            #    Output('max-consecutive-occurrence-table', 'children'),
               Output('probability-table', 'children'),
               Output('inference-rate-text', 'children'),
               Output('latency-text', 'children'),
               Output('power-consumption-text', 'children'),
               Output('consecutive-count-text', 'children'),
               Output('damage-dealt-text', 'children'),
               Output('previous-roll-image', 'src'),
               Output('current-roll-image', 'src'),
               Output('progress-bar', 'value'),
               Output('health-text', 'children'),
               Output('max-damage-text', 'children'),],
              [Input('interval-component', 'n_intervals')])
def update_data(n_intervals):
    global df, max_consecutive_occurrences, total_rolls, consecutive_count, current_roll, progress_value, max_damage

    # Load the data from the dice_roll_data.csv file into a Pandas DataFrame
    df = pd.read_csv('dice_roll_data.csv')

    # Calculate statistics
    result_counts = df['roll'].value_counts().sort_index()
    total_rolls = result_counts.sum()

    # Create figure with px.bar
    fig = px.bar(y=result_counts.index, x=result_counts.values, labels={'x': 'Compte', 'y': 'Résultat'},
                 orientation='h')

    # Update layout for the bar chart to make the axis titles and tick labels larger
    fig.update_xaxes(tickfont=dict(size=24), title_font=dict(size=28))
    fig.update_yaxes(tickfont=dict(size=24), title_font=dict(size=28))

    # Add numbers on the bars
    fig.update_traces(text=result_counts.values, textposition='inside', textfont_size=20)

    # Calculate the maximal consecutive occurrence for each roll
    max_consecutive_occurrences = {roll: find_max_consecutive_occurrence(df['roll'], roll) for roll in range(1, 7)}

    # Calculate the total and maximal damage dealt and apply it to the progress bar
    total_damage_dealt = sum(calculate_cumulative_damage(df['roll']))
    progress_value = max_progress_value - total_damage_dealt
    health_text = f'Points de vie: {progress_value:.0f}/{max_progress_value}'

    # Update the table in Cell 2 with the new max consecutive occurrences
    max_occurrence_table = [
        html.Thead(
            html.Tr([html.Th('Résultat', style={'font-size': '28px'}), html.Th('Occurence Consécutive Max', style={'font-size': '28px'})])
        ),
        html.Tbody(
            [html.Tr([html.Td(f'{roll}', style={'font-size': '24px'}), html.Td(f'{max_consecutive_occurrences[roll]}', style={'font-size': '24px'})]) for roll in range(1, 7)]
        )
    ]

    # Read values from the info.txt file
    inference_rate, latency, power_consumption = read_info_file()

    # Update text in Cell 2 with values from info.txt
    inference_rate_text = f"Débit d'Inference: {inference_rate} fps" if inference_rate is not None else "Débit d'Inference: N/A"
    latency_text = f'Latence: {latency} µs' if latency is not None else 'Latence: N/A'
    power_consumption_text = f'Consomation Énergétique: {power_consumption} W' if power_consumption is not None else 'Consomation Énergétique: N/A'

    # Calculate probabilities
    probabilities = result_counts / total_rolls * 100
    probability_table = [
        html.Thead(
            html.Tr([html.Th('Résultat', style={'font-size': '28px'}), html.Th('Probabilités', style={'font-size': '28px'})])
        ),
        html.Tbody(
            [html.Tr([html.Td(f'{roll}', style={'font-size': '24px'}), html.Td(f'{probabilities[roll]:.2f}%', style={'font-size': '24px'})]) for roll in range(1, 7)]
        )
    ]

    # Update consecutive count and text
    current_roll = df['roll'].iloc[-1] if not df.empty else 0
    consecutive_count = sum(1 for _ in itertools.takewhile(lambda x: x == current_roll, reversed(df['roll'])))
    consecutive_count_text = f'Vous avez lancé {current_roll} pour la {consecutive_count}{"ère" if consecutive_count == 1 else "ème"} fois de suite!'

    # Calculate damage dealt
    damage_dealt = current_roll * (2 ** (consecutive_count-1))
    damage_dealt_text = f'Dégat infligé: {damage_dealt}'

    # Calculate max damage dealt
    if max_damage > damage_dealt:
        max_damage_text = f'Dégat Maximal: {max_damage}'
    else:
        max_damage = damage_dealt
        max_damage_text = f'Nouveau Dégat Maximal: {max_damage}! Bravo!'

    # Get image sources based on the current and previous rolls
    previous_roll_image_source = Image.open('assets/previous_roll.jpg')
    current_roll_image_source = Image.open('assets/current_roll.jpg')

    return fig, f'Total de tirs: {total_rolls}', probability_table, inference_rate_text, latency_text, power_consumption_text, consecutive_count_text, damage_dealt_text, previous_roll_image_source, current_roll_image_source, progress_value, health_text, max_damage_text


if __name__ == '__main__':
    app.run_server(debug=True, host='0.0.0.0', dev_tools_hot_reload=False)
