# -*- coding: utf-8 -*-
"""
Created on Wed Dec 18 11:49:01 2024

@author: ym
"""
import os
import pickle
import numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
from scipy.spatial.distance import cdist
from utils.tools import init_eventDict

def read_eventdict(eventDataPath):
    evtDict = {}
    for filename in os.listdir(eventDataPath):
        evtname, ext = os.path.splitext(filename)
        if ext != ".pickle": continue

        evtpath = os.path.join(eventDataPath, filename)
        with open(evtpath, 'rb') as f:  
            evtdata = pickle.load(f)
        evtDict[evtname] = evtdata
    
    
    return evtDict

def simi_calc(event, o2nevt, pattern, typee=None):
    if pattern==1 or pattern==2:
        if typee == "11":
            boxes1 = event.front_boxes
            boxes2 = o2nevt.front_boxes
            
            feat1 = event.front_feats
            feat2 = o2nevt.front_feats
        if typee == "10":
            boxes1 = event.front_boxes
            boxes2 = o2nevt.back_boxes
            
            feat1 = event.front_feats
            feat2 = o2nevt.back_feats
        if typee == "00":
            boxes1 = event.back_boxes
            boxes2 = o2nevt.back_boxes
            
            feat1 = event.back_feats
            feat2 = o2nevt.back_feats
        if typee == "01":
            boxes1 = event.back_boxes
            boxes2 = o2nevt.front_boxes
            
            feat1 = event.back_feats
            feat2 = o2nevt.front_feats
    
    '''自定义事件特征选择'''    
    if pattern==3 and len(event.feats_compose) and len(o2nevt.feats_compose):
        feat1 = [event.feats_compose]
        feat2 = [o2nevt.feats_compose]

    if len(feat1) and len(feat2):
        matrix = 1 - cdist(feat1[0], feat2[0], 'cosine')
        simi = np.mean(matrix)
    else:
        simi = None
    return simi


def one2n_pr(evtDicts, pattern=1):
    '''
    pattern:
        1: process.data 中记录的相似度
        2: 根据 process.data 中标记的 type 选择特征组合方式计算相似度
        3: 利用 process.data 中的轨迹特征，以其它方式计算相似度
    '''
    tpevents, fnevents, fpevents, tnevents = [], [], [], []
    tpsimi, fnsimi, tnsimi, fpsimi = [], [], [], []
    one2nFile, errorFile_one2n = [], []
    errorFile_one2n_ = []
    evts_output = []
    for evtname, event in evtDicts.items():
        evt_names, evt_barcodes, evt_similars, evt_types = [], [], [], []        
        
        if len(event.one2n)==0 or len(event.barcode)==0:
            continue
        
        evts_output.append(evtname)

        for ndict in event.one2n:
            nname = ndict["event"]
            barcode = ndict["barcode"]
            similar = ndict["similar"]
            typee = ndict["type"].strip()
            
            if len(barcode)==0:
                continue
            if typee.find(",") >=0:
                typee = typee.split(",")[-1]

            if pattern==1:
                evt_similars.append(similar)
            if pattern==2 or pattern==3:
                o2n_evt = [evt for name, evt in evtDicts.items() if name.find(nname[:15])==0]
                if len(o2n_evt)!=1: 
                    continue
                
                simival = simi_calc(event, o2n_evt[0], pattern, typee)
                if simival==None: 
                    continue
                evt_similars.append(simival)
                
            evt_names.append(nname)
            evt_barcodes.append(barcode)
            evt_types.append(typee)
            
        # if evtname == "20250226-170321-327_6903244678377":
        #     print("evtname")

        ## process.data的oneTon的各项中，均不包括当前事件的barcode
        if event.barcode not in evt_barcodes:
            errorFile_one2n.append(evtname)
            continue
        else:
            one2nFile.append(evtname)
                        
        if len(evt_names)==len(evt_barcodes)==len(evt_similars)==len(evt_types) and len(evt_names)>0:    
            # maxsim = evt_similars[evt_similars.index(max(evt_similars))]
            maxsim = max(evt_similars)
            for i in range(len(evt_names)):
                bcd, simi = evt_barcodes[i], evt_similars[i]
                if bcd==event.barcode and simi==maxsim:
                    tpsimi.append(simi)
                    tpevents.append(evtname)
                elif bcd==event.barcode and simi!=maxsim:
                    fnsimi.append(simi)
                    fnevents.append(evtname)
                elif bcd!=event.barcode and simi!=maxsim: 
                    tnsimi.append(simi)
                    tnevents.append(evtname)
                elif bcd!=event.barcode and simi==maxsim and event.barcode in evt_barcodes:
                    fpsimi.append(simi)
                    fpevents.append(evtname)
                else:
                    errorFile_one2n_.append(evtname)
     
    ''' 1:n 数据存储，需根据相似度排序'''
    PPrecise, PRecall = [], []
    NPrecise, NRecall = [], []
    Thresh = np.linspace(-0.2, 1, 100)
    for th in Thresh:
        '''============================= 1:n 计算'''
        TP = sum(np.array(tpsimi) >= th)
        FP = sum(np.array(fpsimi) >= th)
        FN = sum(np.array(fnsimi) < th)
        TN = sum(np.array(tnsimi) < th)
        
        PPrecise.append(TP/(TP+FP+1e-6))
        PRecall.append(TP/(TP+FN+1e-6)) 
        NPrecise.append(TN/(TN+FN+1e-6))
        NRecall.append(TN/(TN+FP+1e-6))
        
        
    '''4. ============================= 1:n 曲线,''' 
    fig, ax = plt.subplots()
    ax.plot(Thresh, PPrecise, 'r', label='Precise_Pos: TP/TPFP')
    ax.plot(Thresh, PRecall, 'b', label='Recall_Pos: TP/TPFN')
    ax.plot(Thresh, NPrecise, 'g', label='Precise_Neg: TN/TNFP')
    ax.plot(Thresh, NRecall, 'c', label='Recall_Neg: TN/TNFN')
    ax.set_xlim([0, 1])
    ax.set_ylim([0, 1])
    
    ax.set_xticks(np.arange(0, 1, 0.1))
    ax.set_yticks(np.arange(0, 1, 0.1))
    ax.grid(True, linestyle='--')

    ax.set_title('1:n Precise & Recall')
    ax.set_xlabel(f"Event Num: {len(one2nFile)}")     
    ax.legend()
    plt.show()
    ## ============================= 1:n 直方图'''
    fig, axes = plt.subplots(2, 2)
    axes[0, 0].hist(tpsimi, bins=60, range=(-0.2, 1), edgecolor='black')
    axes[0, 0].set_xlim([-0.2, 1])
    axes[0, 0].set_title(f'TP: {len(tpsimi)}')
    axes[0, 1].hist(fpsimi, bins=60, range=(-0.2, 1), edgecolor='black')
    axes[0, 1].set_xlim([-0.2, 1])
    axes[0, 1].set_title(f'FP: {len(fpsimi)}')
    axes[1, 0].hist(tnsimi, bins=60, range=(-0.2, 1), edgecolor='black')
    axes[1, 0].set_xlim([-0.2, 1])
    axes[1, 0].set_title(f'TN: {len(tnsimi)}')
    axes[1, 1].hist(fnsimi, bins=60, range=(-0.2, 1), edgecolor='black')
    axes[1, 1].set_xlim([-0.2, 1])
    axes[1, 1].set_title(f'FN: {len(fnsimi)}')
    plt.show()
      
    return fpevents
           
def main():  
    '''1. 生成事件字典并保存至 eventDataPath, 只需运行一次 '''
    init_eventDict(eventSourcePath, eventDataPath, stype="realtime")  # 'source', 'data', 'realtime'
    
    # for pfile in os.listdir(eventDataPath):
    #     evt = os.path.splitext(pfile)[0].split('_')
    #     cont =  len(evt)>=2 and evt[-1].isdigit() and len(evt[-1])>=10
    #     if not cont:
    #         continue

    '''2. 读取事件字典 '''
    evtDicts = read_eventdict(eventDataPath)
    
    
    '''3. 1:n 比对事件评估 '''
    fpevents = one2n_pr(evtDicts, pattern=1)

    fpErrFile = str(Path(resultPath).joinpath("one2n_fp_Error.txt"))
    with open(fpErrFile, "w") as file:
        for item in fpevents:
            file.write(item + "\n")
       
            
            
if __name__ == '__main__':
    eventSourcePath  = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\V12\2025-3-4_2"
    resultPath = r"\\192.168.1.28\share\测试视频数据以及日志\全实时测试\testing"
    
    eventDataPath = os.path.join(resultPath, "evtobjs_wang")
    if not os.path.exists(eventDataPath): 
        os.makedirs(eventDataPath) 
        
    # similPath = os.path.join(resultPath, "simidata")
    # if not os.path.exists(similPath): 
    #     os.makedirs(similPath)
    
    main()
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    