import numpy as np
import pandas as pd
from multiprocessing import Pool
from functools import partial
import functools
import warnings
import pickle
from sklearn.linear_model import LogisticRegression

warnings.filterwarnings('ignore')


class SCORE_CARD():
    def __init__(self, continuous_bin_method_path="", discrete_method_path=""):
        '''
        :param continuous_bin_method_path: The path of files that are generated by WOE_ENCODER_CONTINUOUS.export_model()
        :param discrete_method_path: The path of files that are generated by WOE_ENCODER_DISCRETE.export_model()
        '''
        self.continuous_bin_method_path = continuous_bin_method_path
        self.discrete_method_path = discrete_method_path

        try:
            fr = open(self.continuous_bin_method_path, "rb")
            self.continuous_bin_method = pickle.load(fr)
        except:
            self.continuous_bin_method = dict()

        try:
            fr = open(self.discrete_method_path, "rb")
            self.discrete_method = pickle.load(fr)
        except:
            self.discrete_method = dict()

        if len(self.discrete_method) == 0 and len(self.continuous_bin_method) == 0:
            raise FileNotFoundError(
                "File continuous_bin_method_path and discrete_method_path must be found at least one")

    def generate_card(self, LR, path, feature_name, A, B):
        '''
        :param LR: Well trained sklearn.linear_model.LogisticRegression model
        :param path: The output path of score_card
        :param feature_name: the  info contained in list feature_name is the feature sequence in well trained LR
        :param A: total_score = A+B*WOE
        :param B: total_score = A+B*WOE
        :return:
        '''
        w = LR.coef_[0]
        b = LR.intercept_[0]

        with open(path, "w") as k:
            k.write("featureName,valueFrom,valueTo,WOE,score,bin_one,bin_zero" + "\n")
            for index,feature in enumerate(feature_name):
                if feature in self.continuous_bin_method:
                    for item in self.continuous_bin_method[feature]:
                        k.write(feature + "," + str(item["begin"]) + "," + str(item["end"]) + "," + str(
                            item["woe"]) + "," + str(B * item["woe"] * w[index]) + "," + str(item["bin_one"]) + "," + str(item["bin_zero"]) + "\n")

                elif feature in self.discrete_method:
                    for item in self.discrete_method[feature]:
                        k.write(feature + "," + str(item["value"]) + "," + str(item["value"]) + "," + str(
                            item["woe"]) + "," + str(B * item["woe"] * w[index]) + "," + str(
                            item["bin_one"]) + "," + str(item["bin_zero"]) + "\n")

                else:
                    raise ValueError("feature {} has not been processed by WOE encoding".format(feature))

            k.write("\n")
            k.write("The bias score is " + str(A + B * b)+"\n")



    def maxmin_AB(self,max_score=960, max_pro=0.99, min_score=30, min_pro=0.01):
        '''
        :param max_score: The maximum score value of score_card
        :param max_pro: The maximum prediction probability of LR within all samples
        :param min_score: The minimum score value of score_card
        :param min_pro: The minimum prediction probability of LR within all samples
        :return:
        '''
        assert max_score<=1000 and max_score>=0, "the value of max_score must be between 0 and 1000"
        assert min_score <= 1000 and min_score >= 0, "the value of min_score must be between 0 and 1000"
        assert max_pro>0 and max_pro <1, "the value of max_pro must be between 0 and 1"
        assert min_pro > 0 and min_pro < 1, "the value of min_pro must be between 0 and 1"
        assert max_score > min_score, "the value max_score must be large than min_score"

        x1 = np.log(max_pro/(1-max_pro))
        x2 = np.log(min_pro/(1-min_pro))
        B = (max_score-min_score)/(x1-x2)
        A = max_score - B * x1
        return A, B




