from flask import Blueprint, request, jsonify
import dataiku
import pandas as pd
import numpy as np
import json
import dataikuapi
from commons.python.fetch.config_bs import ConfigBs, EnvMode
from credit_scoring import score_and_compute_perf

mode = ConfigBs.mode()

fetch_api = Blueprint("fetch_api",__name__)
client = dataiku.api_client()
if mode == EnvMode.LOCAL.value:
    project_key = "SOL_CREDIT_SCORING"
else:
    project_key = dataiku.get_custom_variables()["projectKey"]
project = client.get_project(project_key)
project_variables = project.get_variables()['standard']
base_points = int(project_variables['points'])
pdo = int(project_variables['points_to_double_odds'])
use_api = bool(project_variables['use_api'])
api_url = project_variables['api_url']

if use_api:
    api_client = dataikuapi.APINodeClient(api_url, "credit_scoring")

score_card_ds = dataiku.Dataset("score_card", project_key=project_key)
score_card = score_card_ds.get_dataframe()

scores_binned_ds = dataiku.Dataset("scores_binned", project_key=project_key)
credit_perf = scores_binned_ds.get_dataframe()

def score_applicant(features):
    applications = pd.DataFrame(features, index=[0])
    applications['id'] = 0
    applications['credit_event'] = 0
    return score_and_compute_perf(score_card, credit_perf, applications)


@fetch_api.route("/api/scorecard")
def get_scorecard():
    nb_features = int(project_variables['nb_features'])
    score_card_dataset = project.get_dataset("score_card_simple_labels")
    score_card = [x for x in score_card_dataset.iter_rows()]
    #variables = list(set([x[0] for x in score_card]))
    variables = {x[0]: x[4] for x in score_card}
    min_score = min(x[2] for x in score_card)
    max_score = max(x[2] for x in score_card)
    categories_scores = [{'title': variables[x], 'variable': x, 'options': [{'label': y[1][:15], 'value': str(y[2]), 
    'linearPercent': str(int((y[2]-min_score)/(max_score-min_score)*90)+10) + '%', 
    'rating': y[3]} for y in sorted(score_card, key=lambda z : z[2]) if y[0] == x]} for x in variables.keys()]
    for i in range(len(categories_scores)):
        categories_scores[i]['id'] = i
        categories_scores[i]['subtitle'] = categories_scores[i]['options'][0]['label']
        categories_scores[i]['score'] = str(categories_scores[i]['options'][0]['value'])
        categories_scores[i]['linearPercent'] = categories_scores[i]['options'][0]['linearPercent']
        categories_scores[i]['rating'] = categories_scores[i]['options'][0]['rating']
    categories_scores = sorted(categories_scores, key=lambda x: max([int(y['value']) for y in x['options']]) - min([int(y['value']) for y in x['options']]), reverse=True)
    max_score = sum(max(int(x['value']) for x in y['options']) for y in categories_scores)
    min_score = sum(min(int(x['value']) for x in y['options']) for y in categories_scores)
    for i in range(len(categories_scores)):
        for j in range(len(categories_scores[i]['options'])):
            categories_scores[i]['options'][j]['rotationValue'] = 18/nb_features + (int(categories_scores[i]['options'][j]['value'])-min_score/nb_features)/(max_score-min_score) * (180 - 18)
        categories_scores[i]['rotation'] = categories_scores[i]['options'][0]['rotationValue']
    return jsonify(categories_scores)

@fetch_api.route("/api/feature_ranges")
def get_feature_ranges():
    feature_ranges_dataset = project.get_dataset("feature_ranges_label")
    feature_ranges = []
    for i, row in enumerate(feature_ranges_dataset.iter_rows()):
        feature_range = {'variable': row[0], 'variable_label': row[6], 'type': row[1], 'score_width': row[5]}
        if row[1] == 'numeric':
            feature_range['min'] = row[2]
            feature_range['max'] = row[3]
            feature_range['values'] = []
        else:
            feature_range['min'] = 0
            feature_range['max'] = 0
            feature_range['values'] = row[4].replace('[', '').replace(']', '').replace("'", "").split(', ')
            feature_range['value'] = feature_range['values'][0]
        feature_range['id'] = i
        feature_ranges.append(feature_range)
    feature_ranges = sorted(feature_ranges, key=lambda x: x['score_width'], reverse=True)
    return jsonify(feature_ranges)

@fetch_api.route("/api/score_and_labels", methods=["POST"])
def get_scores_and_labels():
    data = request.get_json()
    features = {d['variable']: ((d['value'] if d['activated'] else np.nan) if d['type']=='numeric' else d['valueString']) for d in data}
    if use_api:
        result = api_client.run_function("score", features = features)
        result = result.get("response")
    else:
        result = score_applicant(features)
    result['labels'] = {k: v[:15] for k, v in result['labels'].items()}
    result['base_points'] = base_points
    result['pdo'] = pdo
    return jsonify(result)