import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import logging
import json
import os
import pandas as pd
from datetime import datetime
from datetime import timedelta
from urllib import parse
import requests


logger = logging.getLogger(__name__)

external_stylesheets = [dbc.themes.DARKLY]

is_cf_instance = os.environ.get('CF_INSTANCE_GUID', '') != ''
port = int(os.environ.get('PORT', 8050))
host = os.environ.get('CF_INSTANCE_INTERNAL_IP', '127.0.0.1')

wml_api_key = os.environ['WML_API_KEY']
wml_scoring_url = os.environ['WML_SCORING_URL']
url = parse.urlparse(wml_scoring_url)
wml_base_url = url._replace(path='').geturl()
wml_instance_id = url.path.split('/')[3]

logger.setLevel(logging.INFO if is_cf_instance else logging.DEBUG)

logger.info('Starting %s server: %s:%d', 'CF' if is_cf_instance else 'local', host, port)

logger.info('WML URL: %s', wml_base_url)
logger.info('WML instance ID: %s', wml_instance_id)

wml_credentials = {
    "apikey": wml_api_key,
    "instance_id": wml_instance_id,
    "url": wml_base_url,
}

iam_token_endpoint = 'https://iam.cloud.ibm.com/identity/token'


def _get_token():
    data = {
        'grant_type': 'urn:ibm:params:oauth:grant-type:apikey',
        'apikey': wml_credentials['apikey']
    }
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(iam_token_endpoint, data=data, headers=headers)
    return response.json()['access_token']


def score(token, algorithm, start_date, country, predict_range, s, i, r):
    headers = {'Authorization': 'Bearer ' + token}
    payload = {
        "fields": ["algorithm", "start_date", "country", "predict_range", "S0", "I0", "R0"],
        "values": [[algorithm, start_date.strftime('%-m/%-d/%y'), country, predict_range, s, i, r]]
    }
    logger.info('Scoring with payload: %s', json.dumps(payload))
    response = requests.post(wml_scoring_url, json=payload, headers=headers)
    if response.status_code == 200:
        result = response.json()
    else:
        raise Exception('Scoring error [{}]: {}'.format(response.status_code, response.text))
    n_days = len(result['values'])
    index = [(start_date + timedelta(days=i)).strftime('%d/%m/%y') for i in range(n_days)]
    return pd.DataFrame(result['values'], columns=result['fields'], index=index)


def serve_layout():
    token = _get_token()
    # predict_range = 14
    # sir_result = score(token, 'SIR', datetime(2020, 3, 3), 'Poland', predict_range, 10_000, 20, 10)
    # logistic_result = score(token, 'LOGISTIC', datetime(2020, 3, 3), 'Poland', predict_range, 10_000, 20, 10)
    calibration_result = score(token, 'CALIBRATION', datetime(2020, 1, 22), 'Poland', 40, 10_000, 20, 10)

    # days = list(sir_result.index)
    days = list(calibration_result.index)

    calibration_result['ActualChange'] = calibration_result['Actual'] - calibration_result['Actual'].shift(1, fill_value=0)
    calibration_result['PredictedChange'] = calibration_result['Predicted'] - calibration_result['Predicted'].shift(1, fill_value=0)

    fig = make_subplots(specs=[[{"secondary_y": True}]])

    fig.add_trace(
        go.Bar(x=days, y=calibration_result['PredictedChange'], name='Predicted Change', opacity=0.5),
        secondary_y=True,
    )
    fig.add_trace(
        go.Bar(x=days, y=calibration_result['ActualChange'], name='Actual Change', opacity=0.5),
        secondary_y=True,
    )
    fig.add_trace(
        go.Scatter(x=days, y=calibration_result['Predicted'], name='Calibration'),
        secondary_y=False,
    )
    fig.add_trace(
        go.Scatter(x=days, y=calibration_result['Actual'], name='Actual', mode="markers", marker=dict(size=8)),
        secondary_y=False,
    )

    fig.update_layout(
        title="Prediction of confirmed cases for Poland",
        template="plotly_dark",
        height=900
    )

    fig.update_xaxes(title_text="Date")

    fig.update_yaxes(title_text="Total confirmed cases", secondary_y=False, range=[0, 6000])
    fig.update_yaxes(title_text="New cases per day", secondary_y=True, range=[0, 1000])

    # fig = go.Figure(
    #     data=[
    #         go.Scatter(x=days, y=sir_result['I'], name='SIR'),
    #         go.Scatter(x=days, y=logistic_result['I'], name='Logistic'),
    #     ],
    #     layout=go.Layout(
    #         title="COVID19 infected prediction in Poland",
    #         template="plotly_dark",
    #         height=600
    #     )
    # )

    return html.Div(children=[
        html.H1(children='COVID-19 Predictions with Watson Machine Learning'),


        dcc.Graph(
            id='example-graph',
            figure=fig
        )
    ])


app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = serve_layout

if __name__ == '__main__':
    app.run_server(debug=(not is_cf_instance), port=port, host=host)

[((369, 396), 'logging.getLogger', 'logging.getLogger', (['__name__'], {}), '(__name__)\n', (386, 396), False, 'import logging\n'), ((552, 606), 'os.environ.get', 'os.environ.get', (['"""CF_INSTANCE_INTERNAL_IP"""', '"""127.0.0.1"""'], {}), "('CF_INSTANCE_INTERNAL_IP', '127.0.0.1')\n", (566, 606), False, 'import os\n'), ((702, 733), 'urllib.parse.urlparse', 'parse.urlparse', (['wml_scoring_url'], {}), '(wml_scoring_url)\n', (716, 733), False, 'from urllib import parse\n'), ((4778, 4840), 'dash.Dash', 'dash.Dash', (['__name__'], {'external_stylesheets': 'external_stylesheets'}), '(__name__, external_stylesheets=external_stylesheets)\n', (4787, 4840), False, 'import dash\n'), ((459, 497), 'os.environ.get', 'os.environ.get', (['"""CF_INSTANCE_GUID"""', '""""""'], {}), "('CF_INSTANCE_GUID', '')\n", (473, 497), False, 'import os\n'), ((515, 543), 'os.environ.get', 'os.environ.get', (['"""PORT"""', '(8050)'], {}), "('PORT', 8050)\n", (529, 543), False, 'import os\n'), ((1480, 1541), 'requests.post', 'requests.post', (['iam_token_endpoint'], {'data': 'data', 'headers': 'headers'}), '(iam_token_endpoint, data=data, headers=headers)\n', (1493, 1541), False, 'import requests\n'), ((2007, 2068), 'requests.post', 'requests.post', (['wml_scoring_url'], {'json': 'payload', 'headers': 'headers'}), '(wml_scoring_url, json=payload, headers=headers)\n', (2020, 2068), False, 'import requests\n'), ((2379, 2448), 'pandas.DataFrame', 'pd.DataFrame', (["result['values']"], {'columns': "result['fields']", 'index': 'index'}), "(result['values'], columns=result['fields'], index=index)\n", (2391, 2448), True, 'import pandas as pd\n'), ((3189, 3235), 'plotly.subplots.make_subplots', 'make_subplots', ([], {'specs': "[[{'secondary_y': True}]]"}), "(specs=[[{'secondary_y': True}]])\n", (3202, 3235), False, 'from plotly.subplots import make_subplots\n'), ((1971, 1990), 'json.dumps', 'json.dumps', (['payload'], {}), '(payload)\n', (1981, 1990), False, 'import json\n'), ((2788, 2809), 'datetime.datetime', 'datetime', (['(2020)', '(1)', '(22)'], {}), '(2020, 1, 22)\n', (2796, 2809), False, 'from datetime import datetime\n'), ((3264, 3362), 'plotly.graph_objects.Bar', 'go.Bar', ([], {'x': 'days', 'y': "calibration_result['PredictedChange']", 'name': '"""Predicted Change"""', 'opacity': '(0.5)'}), "(x=days, y=calibration_result['PredictedChange'], name=\n    'Predicted Change', opacity=0.5)\n", (3270, 3362), True, 'import plotly.graph_objects as go\n'), ((3418, 3509), 'plotly.graph_objects.Bar', 'go.Bar', ([], {'x': 'days', 'y': "calibration_result['ActualChange']", 'name': '"""Actual Change"""', 'opacity': '(0.5)'}), "(x=days, y=calibration_result['ActualChange'], name='Actual Change',\n    opacity=0.5)\n", (3424, 3509), True, 'import plotly.graph_objects as go\n'), ((3566, 3639), 'plotly.graph_objects.Scatter', 'go.Scatter', ([], {'x': 'days', 'y': "calibration_result['Predicted']", 'name': '"""Calibration"""'}), "(x=days, y=calibration_result['Predicted'], name='Calibration')\n", (3576, 3639), True, 'import plotly.graph_objects as go\n'), ((4606, 4675), 'dash_html_components.H1', 'html.H1', ([], {'children': '"""COVID-19 Predictions with Watson Machine Learning"""'}), "(children='COVID-19 Predictions with Watson Machine Learning')\n", (4613, 4675), True, 'import dash_html_components as html\n'), ((4687, 4728), 'dash_core_components.Graph', 'dcc.Graph', ([], {'id': '"""example-graph"""', 'figure': 'fig'}), "(id='example-graph', figure=fig)\n", (4696, 4728), True, 'import dash_core_components as dcc\n'), ((2304, 2321), 'datetime.timedelta', 'timedelta', ([], {'days': 'i'}), '(days=i)\n', (2313, 2321), False, 'from datetime import timedelta\n')]