from sklearn.preprocessing import label_binarize
from sklearn.metrics import precision_recall_curve, average_precision_score
import matplotlib.pyplot as plt
import numpy as np
# from utils.config import conf
import os


# def show_multiclass_pr(y_true, y_scores):  # 多分类
#     # 将真实标签二值化
#     y_true_binarized = label_binarize(y_true, classes=np.arange(conf.n_classes))
#
#     # 计算每个类别的PR曲线和平均精度
#     precision = dict()
#     recall = dict()
#     average_precision = dict()
#
#     for i in range(conf.n_classes):
#         precision[i], recall[i], _ = precision_recall_curve(y_true_binarized[:, i], y_scores[:, i])
#         average_precision[i] = average_precision_score(y_true_binarized[:, i], y_scores[:, i])
#
#     # 计算微平均PR曲线和平均精度
#     precision["micro"], recall["micro"], _ = precision_recall_curve(y_true_binarized.ravel(), y_scores.ravel())
#     average_precision["micro"] = average_precision_score(y_true_binarized, y_scores, average="micro")
#
#     # 计算宏平均PR曲线和平均精度
#     precision["macro"] = np.mean([precision[i] for i in range(conf.n_classes)], axis=0)
#     recall["macro"] = np.mean([recall[i] for i in range(conf.n_classes)], axis=0)
#     average_precision["macro"] = np.mean([average_precision[i] for i in range(conf.n_classes)])
#
#     # 绘制微平均PR曲线
#     plt.figure(figsize=(10, 7))
#     plt.plot(recall["micro"], precision["micro"], color='gold', lw=2,
#              label='micro-average Precision-recall curve (area = {0:0.2f})'
#                    ''.format(average_precision["micro"]))
#
#     # 绘制宏平均PR曲线
#     plt.plot(recall["macro"], precision["macro"], color='navy', lw=2,
#              label='macro-average Precision-recall curve (area = {0:0.2f})'
#                    ''.format(average_precision["macro"]))
#
#     # 绘制每个类别的PR曲线
#     colors = plt.cm.tab20(np.linspace(0, 1, conf.n_classes))
#     for i, color in zip(range(conf.n_classes), colors):
#         plt.plot(recall[i], precision[i], color=color, lw=2,
#                  label='Precision-recall curve of class {0} (area = {1:0.2f})'
#                        ''.format(i, average_precision[i]))
#
#     plt.xlabel('Recall')
#     plt.ylabel('Precision')
#     plt.title('Extension of Precision-Recall curve to multi-class')
#     plt.legend(loc="best")
#     plt.show()
#     pass


def calculate_similarity(outputs, targets, threshold):
    FN, FP, TN, TP = 0, 0, 0, 0
    for output, target in zip(outputs, targets):
        # print("output >> {} , target >> {}".format(output, target))
        if output != target:
            if target == 0:
                FP += 1
            elif target == 1:
                FN += 1
        else:
            if target == 0:
                TN += 1
            elif target == 1:
                TP += 1
    if TP == 0:
        prec, recall = 0, 0
    else:
        prec = TP / (TP + FP)
        recall = TP / (TP + FN)
    if TN == 0:
        tn_prec, tn_recall = 0, 0
    else:
        tn_prec = TN / (TN + FN)
        tn_recall = TN / (TN + FP)
        # print("TP>>{}, FP>>{}, TN>>{}, FN>>{}".format(TP, FP, TN, FN))
    if threshold == 0.1:
        print("TP>>{}, FP>>{}, TN>>{}, FN>>{}".format(TP, FP, TN, FN))
    return prec, recall, tn_prec, tn_recall


def show_pr(prec, recall, tn_prec, tn_recall, thres, title_name):
    x = thres
    plt.figure(figsize=(10, 6))
    plt.plot(x, recall, color='red', label='recall:TP/TPFN')
    plt.plot(x, tn_recall, color='black', label='recall_TN:TN/TNFP')
    plt.plot(x, prec, color='blue', label='PrecisePos:TP/TPFN')
    plt.plot(x, tn_prec, color='green', label='PreciseNeg:TN/TNFP')
    plt.legend()
    plt.xlabel('threshold')
    # if self.title_name is not None:
    plt.title(title_name)
    plt.grid(True, linestyle='--', alpha=0.5)
    plt.savefig(os.sep.join(['../pr_test', 'yolo_pr.png']))
    plt.show()
    plt.close()


def write_results_to_file(title_name, thres, recall, recall_TN, PrecisePos, PreciseNeg):
    file_path = os.sep.join(['../pr_test', title_name + '.txt'])
    with open(file_path, 'w') as file:
        file.write("threshold,   recall,   recall_TN,   PrecisePos,   PreciseNeg\n")
        for thre, rec, rec_tn, prec_pos, prec_neg in zip(thres, recall, recall_TN, PrecisePos, PreciseNeg):
            file.write(
                f"thre>>{thre:.2f},  recall>>{rec:.4f},  precise_pos>>{prec_pos:.4f},  recall_tn>>{rec_tn:.4f},  precise_neg>>{prec_neg:4f}\n")


def show_to_pr(y_true, y_prob, type):  # 二分类
    thres = [i * 0.01 for i in range(101)]
    title_name = 'yolo_pr'
    recall, recall_TN, PrecisePos, PreciseNeg = [], [], [], []
    for threshold in thres:
        y_scores_adjusted = []
        if type == 0:
            y_scores_adjusted = np.where(y_prob < threshold, 0, 1)
        elif type == 1:
            for yp in y_prob:
                if yp != 0:
                    yp = np.array(yp)
                    yp_num = np.sum(np.array(yp) > threshold)
                    if yp_num / len(yp) > 0.1:
                        y_scores_adjusted.append(1)
                    else:
                        y_scores_adjusted.append(0)
                else:
                    y_scores_adjusted.append(0)
        prec, pos_recall, tn_prec, tn_recall = calculate_similarity(y_scores_adjusted, y_true, threshold)
        recall.append(pos_recall)
        recall_TN.append(tn_recall)
        PrecisePos.append(prec)
        PreciseNeg.append(tn_prec)
        # print(" prec>>{}  recall>>{}   tn_prec>>{}  tn_recall>>{} threshold>>{}\n".format(prec, pos_recall, tn_prec,
        #                                                                                   tn_recall, threshold))
    show_pr(PrecisePos, recall, PreciseNeg, recall_TN, thres, title_name)
    write_results_to_file(title_name, thres, recall, recall_TN, PrecisePos, PreciseNeg)


if __name__ == '__main__':
    pass
