from django.core.management.base import BaseCommand, CommandError
import pandas as pd
import itertools as it
from collections import defaultdict, Counter
import json
from dubletten_tool.models import PersonProxy, Group, Suggestions, StatusButtonProxyType, StatusButtonGroupType, StatusButtonGroup, StatusButtonProxyType, StatusButtonProxy
from apis_core.apis_entities.models import Person
from apis_core.apis_metainfo.models import Collection
import logging
from django.contrib.auth.models import User
from dubletten_tool.logger import init_logger


log = logging.getLogger("DBLogger")

user = User.objects.get(username="GPirgie")

class Command(BaseCommand):

    def create_new_groups(self, per_set):
        selection = Person.objects.filter(id__in=[p.id for p in per_set])
        df_per = pd.DataFrame(selection.values("id","name", "first_name", "gender", "start_date", "end_date", "start_date_written", "end_date_written")).set_index("id")
        per = df_per[["name", "first_name", "gender", "start_date", "end_date", "start_date_written", "end_date_written"]]
        per["sd"] = [str(d) for d in per["start_date"]]
        per["ed"] = [str(d) for d in per["end_date"]]

        self.stdout.write("Calculating Groups Started")
        for idx, (d, group) in enumerate(per.groupby(["name", "first_name", "gender", "sd", "ed"])):
            bd, dd = d[3], d[4]
            bd = bd.replace("None", "")
            dd = dd.replace("None", "")
            if len(group) > 1:
                if bd and dd:
                    name = (f"{d[0]}, {d[1]} [B+D]")
                elif bd:
                    name = (f"{d[0]}, {d[1]} [B]")
                elif dd:
                    name = (f"{d[0]}, {d[1]} [D]")
                else:
                    name = (f"{d[0]}, {d[1]}")
                    
                name += " {ACC}"

                g, c = Group.objects.get_or_create(name=name)
                log.info(f"CREATED GROUP {g.id}, with name {g.name}", extra={"user":user, "action": "SETUP GROUP: Created Group"})
                index = group.index.to_list()
                for ix in index:
                    gm, c = PersonProxy.objects.get_or_create(person=Person.objects.get(id=ix))
                    gm.status="candidate"
                    gm.save()
                    g.members.add(gm)
                g._gender = d[2]
                g.save()
                log.info(f"GROUP {g.id}, with name {g.name} has members {[{'proxy_id':p.id, 'person_id':p.person.id, 'status':p.status} for p in g.members.all()]}", extra={"user":user, "action": "SETUP GROUP: Added Members"})


            elif len(group) == 1:
                s = group.index.to_list()[0]
                per = Person.objects.get(id=s)
                prox, c = PersonProxy.objects.get_or_create(person=per)
                prox.status = "single"
                prox.save()
                log.info(f"CREATED SINGLE {prox.id} with name {prox.name} and person_id {prox.person.id} with status {prox.status}", extra={"user":user, "action": "SETUP GROUP: Created Single"})
        self.stdout.write("Finished: Calculating Groups")

    # copied over from management commands
    def create_ampel_buttons(self):
        self.stdout.write(f"Starting Create Ampel Buttons")
        types = [("Checked Members", "CM" ),("Checked Suggestions", "CSu" ),("Checked Singles", "CSi"),("Ready To Merge", "RM")]
        for el in types:
            btn, c = StatusButtonGroupType.objects.get_or_create(name=el[0], short=el[1])
            btn.add_to_all_groups()
            self.stdout.write(f"Added Button '{el[0]} to all Groups.")


    # copied over from management commands
    def calculate_names(self):
        #self.stdout.write("Started: Calculate Names")

        for p in PersonProxy.objects.all():
            p._names = p.names_list
            p._first_names = p.first_names_list
            p.save()

        sn = {tuple(s.allnames) for s in PersonProxy.objects.all()}
        sn = [set(el) for el in sn]
        all_sn = {part for el in sn for part in el}

        sf = {tuple(s.allfirst_names) for s in PersonProxy.objects.all()}
        sf = [set(el) for el in sf]
        all_sf = {part for el in sf for part in el}


        p_n = defaultdict(list)
        p_f = defaultdict(list)
        [p_n[tuple(p.allnames)].append(p.id) for p in PersonProxy.objects.all()]    
        [p_f[tuple(p.allfirst_names)].append(p.id) for p in PersonProxy.objects.all()]    

        #self.stdout.write("step 1 finished")

        def get_names(names_set, res_dic):
            #self.stdout.write("running get names")
            res = defaultdict(list)
            for n in names_set:
                for k in res_dic:
                    if n in k:
                        res[n] += res_dic[k]
            return res

        res_n = get_names(all_sn, p_n)
        res_f = get_names(all_sf, p_f)

        #self.stdout.write("step 2 finished, get names done")

        def get_per_dic(data):
            #self.stdout.write("running get_per_dic")
            per_dic = defaultdict(set)
            for idx, i in enumerate(PersonProxy.objects.values_list("id")):
                test = i[0]
                for k, v in data.items():
                    if test in v:
                        per_dic[test] = per_dic[test].union(set(v))
                        per_dic[test].remove(test)
            return per_dic

        n = get_per_dic(res_n)
        f = get_per_dic(res_f)
        #self.stdout.write("finished all calculations")

        full_res = defaultdict(set)

        for k,v in n.items():

            v2 = f[k]
            res = v.intersection(v2)
            if res:
                full_res[k] = res
            else:
                full_res[k] = set()

        data = {k:list(v) for k, v in full_res.items()}
        # with open("/Users/gregorpirgie/Desktop/full_res_new.json", "w") as file:
        #     data = json.dumps({k:list(v) for k, v in full_res.items()})
        #     file.write(data)
        #self.stdout.write("Finished: Calculate Names")

        return data


  
    def handle(self, *args, **options):
        nopps = [p for p in Person.objects.all() if not hasattr(p, "personproxy")]
        no_vorfins_no_proxies = [p for p in nopps if not "vorfin" in p.name]
        self.create_new_groups(no_vorfins_no_proxies)
        self.create_ampel_buttons()
        data = self.calculate_names()
        Suggestions.objects.all().delete()
        Suggestions.objects.get_or_create(data=data)
        self.stdout.write("All processes finished.")


    


