from collections import defaultdict
import glob
import json
from pathlib import Path
import pathlib
from time import sleep
import pandas as pd

from tqdm import tqdm
import os
import requests
# from mmlrestclient as metamapliteclient
from enum import Enum
from ddi_fw.utils import create_folder_if_not_exists


# data = '''
# Lepirudin is a recombinant hirudin formed by 65 amino acids that acts as a highly specific and direct thrombin inhibitor.
# [L41539,L41569] Natural hirudin is an endogenous anticoagulant found in _Hirudo medicinalis_ leeches.
# [L41539] Lepirudin is produced in yeast cells and is identical to natural hirudin except for the absence of sulfate
# on the tyrosine residue at position 63 and the substitution of leucine for isoleucine at position 1 (N-terminal end).[A246609]

# Lepirudin is used as an anticoagulant in patients with heparin-induced thrombocytopenia (HIT),
# an immune reaction associated with a high risk of thromboembolic complications.[A3, L41539]
# HIT is caused by the expression of immunoglobulin G (IgG) antibodies that bind to the complex formed by heparin and platelet factor 4.
# This activates endothelial cells and platelets and enhances the formation of thrombi.
# [A246609] Bayer ceased the production of lepirudin (Refludan) effective May 31, 2012.[L41574]'''

# response = requests.post(url, data=data)

# print(response.content)

HERE = pathlib.Path(__file__).resolve().parent


class CTakesNER:
    def __init__(self, drugs_df = None,api_url= 'http://localhost:8080/ctakes-web-rest/service/analyze?pipeline=Default'
                  , output_path='ner-output/ctakes', ids=[],
                 columns=[]):
        self.drugs_df =  drugs_df
        self.api_url = api_url
        self.columns = columns
        self.ids = ids
        self.output_path = output_path

    def run(self, 
            run_for=[]):

        for column in self.columns:
            if not os.path.exists(self.output_path+"/"+column):
                os.makedirs(self.output_path+"/"+column)
        for column in self.columns:
            column_output_path = self.output_path+'/'+column
            if not column in run_for:
                continue
            # not include
            if self.ids:
                self.drugs_df = self.drugs_df[~self.drugs_df['drugbank_id'].isin(
                    self.ids)]
            for index, row in self.drugs_df.iterrows():
                drugbank_id = row['drugbank_id']
                data = row[column]
                if data is None or pd.isna(data) or (type(data) == str and len(data.strip()) == 0):  # or len(data) == 0:
                    with open(f'{column_output_path}/{drugbank_id}.json', 'w', encoding='utf-8') as f:
                        json.dump([], f, ensure_ascii=False, indent=4)
                    continue
                data = data.encode()
                response = requests.post(self.api_url, data=data)

                with open(f'{column_output_path}/{drugbank_id}.json', 'w', encoding='utf-8') as f:
                    try:
                        obj = json.loads(response.text)
                        json.dump(obj, f, ensure_ascii=False, indent=4)
                    except:
                        # print(f'{drugbank_id} is not parsable')
                        json.dump([], f, ensure_ascii=False, indent=4)
                        continue

                # if index % 10 == 0:
                #     sleep(10)

    def load(self, filename = None, group = True):
        file_path=  filename if filename else HERE.joinpath('output/ctakes/ctakes_ner.pkl')
        df = pd.read_pickle(file_path)

        if group:
            keys = list(df.columns.values)

            df['tui'] = [[]] * df.shape[0]
            df['cui'] = [[]] * df.shape[0]
            df['entities'] = [[]] * df.shape[0]

            tui_columns = [key for key in keys if key.startswith('tui')]
            cui_columns = [key for key in keys if key.startswith('cui')]
            entities_columns = [key for key in keys if key.startswith('entities')]
            #bunu tek bir eşitlikle çöz
            df['tui'] =  df[tui_columns].values.tolist()
            df['tui'] = df['tui'].apply(lambda items:{i for item in items for i in item})  

            df['cui'] =  df[cui_columns].values.tolist()
            df['cui'] = df['cui'].apply(lambda items:{i for item in items for i in item})  

            df['entities'] =  df[entities_columns].values.tolist()
            df['entities'] = df['entities'].apply(lambda items:{i for item in items for i in item})  

        return df

    def create_dataframe(self, override = False):  # dataframe_columns=[]
        filename='ctakes_ner.pkl'
        if not override and os.path.exists(self.output_path+"/" + filename):
            return self.load(self.output_path+"/" + filename)
        
        create_folder_if_not_exists(self.output_path+"/" + filename)
        dict_of_dict = defaultdict(dict)
        for column in self.columns:
            all_json_files = f'{self.output_path}/{column}/'+'*.json*'
            for filepath in tqdm(glob.glob(all_json_files)):
                with open(filepath, 'r', encoding="utf8") as f:
                    file_name = Path(f.name).stem
                    t = dict_of_dict[file_name]
                    data = json.load(f)
                    entities = []
                    cuis = []
                    tuis = []
                    if data is None or len(data) == 0:
                        t['drugbank_id'] = file_name
                        t[f'cui_{column}'] = []
                        t[f'tui_{column}']= []
                        t[f'entities_{column}'] = []
                        dict_of_dict[file_name] = t
                        continue
                    for key, value in data.items():
                        entities = [v['text'] for v in value]
                        cuis = [attr['cui']
                                for v in value for attr in v['conceptAttributes']]
                        tuis = [attr['tui']
                                for v in value for attr in v['conceptAttributes']]
                        # codingScheme
                    
                    if 'drugbank_id' not in t:
                        t['drugbank_id'] = file_name
                    t[f'cui_{column}'] = cuis
                    t[f'tui_{column}'] = tuis
                    t[f'entities_{column}'] = entities
                dict_of_dict[file_name] = t

        df = pd.DataFrame(dict_of_dict.values(),
                          #   orient='index',
                          #   columns=columns
                          )
        df.to_pickle(self.output_path+"/" + filename)
        # dataframe_columns.insert(0, 'drugbank_id')

        # new_columns = {columns[i]: dataframe_columns[i]
        #                for i in range(len(columns))}
        # df.rename(columns=new_columns, inplace=True)
        return df


# no module named 'mmlrestclient'
# class MMSLiteNER:

#     # https://ii.nlm.nih.gov/metamaplite/js/formControls.js

#     class Groups(Enum):

#         activities_group = ['acty', 'bhvr', 'dora',
#                             'evnt', 'gora', 'inbe', 'mcha', 'ocac', 'socb']

#         anatomy_group = ['anst', 'blor', 'bpoc', 'bsoj', 'bdsu',
#                          'bdsy', 'cell', 'celc', 'emst', 'ffas', 'tisu']

#         checmicals_and_drugs_group = ['aapp', 'antb', 'bacs', 'bodm', 'carb', 'chem', 'chvf', 'chvs',
#                                       'clnd', 'eico', 'elii', 'enzy', 'hops', 'horm', 'imft',
#                                       'irda', 'inch', 'lipd', 'nsba', 'nnon', 'orch', 'opco',
#                                       'phsu', 'rcpt', 'strd', 'vita']

#         concept_and_ideas_group = ['clas', 'cnce', 'ftcn', 'grpa', 'idcn', 'inpr', 'lang',
#                                    'qlco', 'rnlw', 'spco', 'tmco']

#         devices_group = ['drdd', 'medd', 'resd']

#         disorders_group = ['acab', 'anab', 'bact', 'comd', 'cgab', 'dsyn',
#                            'emod', 'fndg', 'inpo', 'mobd', 'patf', 'sosy']

#         # abbreviated disorders group, finding and congenital abnormality removed
#         disorders_abbrev_group = ['acab', 'anab', 'bact', 'cgab', 'dsyn',
#                                   'emod', 'inpo', 'mobd', 'patf', 'sosy']

#         genes_and_molecular_sequences = [
#             'amas', 'crbs', 'gngm', 'mosq', 'nusq']

#         geographic_areas = ['geoa']

#         living_being = ['aggp', 'amph', 'anim', 'arch', 'bact', 'bird', 'euka', 'fish',
#                         'fngs', 'grup', 'humn', 'mamm', 'orgm', 'podg',
#                         'plnt', 'popg', 'prog', 'rept', 'vtbt', 'virs']

#         objects = ['enty', 'food', 'mnob', 'sbst']

#         occupations = ['bmod', 'ocdi']

#         organizations = ['hcro', 'orgt', 'pros', 'shro']

#         phenomena = ['eehu' 'hcpp', 'lbtr', 'npop', 'phpr']

#         physiology = ['celf', 'clna', 'clnd']

#         procedures = ['diap', 'edac', 'hlca', 'lbpr', 'mbrt', 'resa', 'topp']

#     def __init__(self, drugs_df, input_path='drugbank/output', output_path='ner-output/metamaplite', ids=[],
#                  columns=[],
#                  included_groups: Groups = [],
#                  excluded_groups: Groups = [],
#                  ):

#         self.drugs_df = drugs_df
#         self.columns = columns
#         self.ids = ids
#         self.output_path = output_path
#         self.included_groups = set()
#         for i, g in enumerate(included_groups):
#             for v in g.value:
#                 self.included_groups.add(v)

#         self.excluded_groups = set()
#         for i, g in enumerate(excluded_groups):
#             for v in g.value:
#                 self.excluded_groups.add(v)

#         for column in columns:
#             if not os.path.exists(output_path+"/"+column):
#                 os.makedirs(output_path+"/"+column)

#     def run_ner(self):
#         # # url = 'https://ii-public1.nlm.nih.gov/metamaplite/rest/annotate'
#         base_url = 'https://ii.nlm.nih.gov/metamaplite/rest/annotate'
#         acceptfmt = 'text/plain'
#         for column in self.columns:
#             column_output_path = self.output_path+'/'+column

#             if self.ids:
#                 self.drugs_df = self.drugs_df[~self.drugs_df['drugbank_id'].isin(
#                     self.ids)]
#             for index, row in self.drugs_df.iterrows():
#                 drugbank_id = row['drugbank_id']
#                 input_text = row[column]
#                 params = [('inputtext', input_text), ('docformat', 'freetext'),
#                           ('resultformat', 'json'), ('sourceString', 'all'),
#                           ('semanticTypeString', 'all')]
#                 resp = metamapliteclient.handle_request(
#                     base_url, acceptfmt, params)

#                 with open(f'{column_output_path}/{drugbank_id}.json', 'w', encoding='utf-8') as f:
#                     obj = json.loads(resp.text)
#                     json.dump(obj, f, ensure_ascii=False, indent=4)

#                 if index % 10 == 0:
#                     sleep(10)

#     def __dict_of_semantic_types__(self, path):
#         m = dict()
#         with open(path, 'r', encoding='utf-8') as f:
#             data = f.read()
#             rows = data.split("\n")
#             for row in rows:
#                 if row != "":
#                     arr = row.split("|")
#                     m[arr[0]] = arr[1]
#         return m

#     def load(self, semantic_type_path: str, dataframe_columns=[]):
#         semantic_type_dict = self.__dict_of_semantic_types__(
#             semantic_type_path)

#         cui_dict = defaultdict(dict)
#         tui_dict = defaultdict(dict)
#         for column in self.columns:
#             all_json_files = f'{self.output_path}/{column}/'+'*.json*'
#             for filepath in tqdm(glob.glob(all_json_files)):
#                 with open(filepath, 'r', encoding="utf8") as f:
#                     file_name = Path(f.name).stem
#                     data = json.load(f)
#                     filtered_obj = [o for o in data if len(o['evlist']) == 1]
#                     # filtered_obj = [o for o in data if len(o['evlist']) == 1 and set(
#                     #     checmicals_and_drugs_group).intersection(set(o['evlist'][0]['conceptinfo']['semantictypes']))]

#                     if self.included_groups:
#                         evaluation = [o['evlist'][0]['conceptinfo'] for o in filtered_obj if len(o['evlist']) == 1
#                                       and
#                                       self.included_groups.intersection(
#                             set(o['evlist'][0]['conceptinfo']['semantictypes']))]
#                         # cuis = [o['evlist'][0]['conceptinfo']['cui'] for o in filtered_obj if len(o['evlist']) == 1
#                         #         and
#                         #         self.included_groups.intersection(
#                         #             set(o['evlist'][0]['conceptinfo']['semantictypes']))]
#                     elif self.excluded_groups:
#                         evaluation = cuis = [o['evlist'][0]['conceptinfo'] for o in filtered_obj if len(o['evlist']) == 1
#                                              and
#                                              not self.excluded_groups.intersection(
#                             set(o['evlist'][0]['conceptinfo']['semantictypes']))]
#                         # cuis = [o['evlist'][0]['conceptinfo']['cui'] for o in filtered_obj if len(o['evlist']) == 1
#                         #         and
#                         #         not self.excluded_groups.intersection(
#                         #             set(o['evlist'][0]['conceptinfo']['semantictypes']))]
#                     else:
#                         evaluation = [o['evlist'][0]['conceptinfo']
#                                       for o in filtered_obj if len(o['evlist']) == 1]
#                         # cuis = [o['evlist'][0]['conceptinfo']['cui']
#                         #         for o in filtered_obj if len(o['evlist']) == 1]

#                     # cuis = [o['evlist'][0]['conceptinfo']['cui'] for o in filtered_obj if len(o['evlist']) == 1 and set(
#                     #     checmicals_and_drugs_group).intersection(set(o['evlist'][0]['conceptinfo']['semantictypes']))]
#                     cuis = [ev['cui'] for ev in evaluation]
#                     semantic_types = [ev['semantictypes'] for ev in evaluation]
#                     tuis = [semantic_type_dict[s]
#                             for semantic_type in semantic_types for s in semantic_type]

#                     d = cui_dict[file_name]
#                     d['drugbank_id'] = file_name
#                     d[column] = set(cuis)

#                     t = tui_dict[file_name]
#                     t['drugbank_id'] = file_name
#                     t[column] = set(tuis)
#                     tui_dict[file_name] = t

#         columns = self.columns
#         columns.insert(0, 'drugbank_id')
#         df = pd.DataFrame(tui_dict.values(),
#                           #   orient='index',
#                           columns=columns
#                           )

#         dataframe_columns.insert(0, 'drugbank_id')

#         new_columns = {columns[i]: dataframe_columns[i]
#                        for i in range(len(columns))}
#         df.rename(columns=new_columns, inplace=True)
#         return df
