import numpy as np
import pandas as pd
import brightway2 as bw
from brightway2 import *
from bw2data.parameters import *
from functions.func_calc_lcia import f_calc_lcia
import global_variables as gv

columns_results = ["path", "am_abs", "lcia_int", "lcia_abs", "code"]
df_results = pd.DataFrame(columns=columns_results)
df_act_to_be_broken_down = pd.DataFrame()
CC_method = gv.CC_method
eidb    = gv.eidb
bio     = gv.bio
bdb     = gv.bdb

def f_recursive_disaggregation_act_to_exc(first_activity, CC_method=CC_method, to_clipboard=False, bdb=bdb, verbose=True):
    global df_act_to_be_broken_down
    global df_results
    global columns_results

    # need to reset these df if function is called twice within runtime
    df_results = pd.DataFrame(columns=columns_results)
    df_act_to_be_broken_down = pd.DataFrame()

    print(f"Starting disaggreation in electricity region {[print(exc.input.as_dict()['location']) for exc in gv.act_NMC_battery_cell.exchanges() if 'electricity' in exc.input.as_dict()['name']]}"
          "\nwith the following parameters activated:")
    for p in DatabaseParameter.select():
        print(p, p.amount)

    ### initialising by adding first row to df_act_to_be_broken_down
    #first_activity = [act for act in bdb if code_first_activity in act['code']][0]
    code_first_activity = first_activity.as_dict()["code"]
    name_first_activity = first_activity.as_dict()["name"]
    score_first_activity = f_calc_lcia(first_activity, CC_method)

    list_data_first_row = [code_first_activity, "$"+name_first_activity, 1, np.nan, score_first_activity, score_first_activity, name_first_activity]
    df_act_to_be_broken_down = pd.concat([df_act_to_be_broken_down, pd.DataFrame([list_data_first_row], columns=["code", "path", "am_abs", "done", "lcia_int", "lcia_abs", "name_l0"])])

    ### executing recursive function using while/break loop
    level = 0
    while True:
        #print("starting row")
        for index, row in df_act_to_be_broken_down.reset_index().iterrows():
            if pd.isna(row["done"]):
        #        print("starting inner row")
                if verbose: print(f"Level {level}: calculating {row['code']} from path {row['path']}")
                else: print(level, end=" ")
                f_break_down_act(row["code"], row["path"], row["am_abs"])
                df_act_to_be_broken_down.loc[(df_act_to_be_broken_down["code"] == row["code"]) & ((df_act_to_be_broken_down["path"].str.contains(row["path"])) | (df_act_to_be_broken_down["path"] == (row["path"]))), "done"] = True  # mark activity as done if it's the activity that has been broken down (cond 1) and it belongs to the correct path trajectory
        level = level + 1
        if not (any(pd.isna(df_act_to_be_broken_down["done"]))):
            if verbose: print(f"breaking now after path {row['path']}")
        #    else: print("done.")
            break

    # adding first(reference) activity row
    df_results = pd.concat([df_results,
                            df_act_to_be_broken_down.loc[df_act_to_be_broken_down["code"] == code_first_activity].drop(
                                "done", axis=1)])

    # adding relative lcia column
    df_results["lcia_rel"] = df_results["lcia_abs"] / \
                             df_results.loc[df_results["code"] == code_first_activity, "lcia_abs"].iloc[0]

    ### cosmetics and copying
    cols = df_results.columns.tolist()
    cols.remove("path")
    cols.insert(4, "path")
    cols.remove("lcia_rel")
    cols.insert(2, "lcia_rel")
    cols = cols[6:] + cols[0:6]

    df_results = df_results[cols].sort_values(by=list(df_results.columns)).reset_index(drop=True)

    # copying to clipboard
    if to_clipboard: df_results.to_clipboard()
    print("\ncompleted disaggregation\n")
    return df_results


def f_break_down_act(parent_activity_code, parent_path="$", parent_am_abs=1, bdb=bdb, columns_results=columns_results):
    global df_act_to_be_broken_down
    global df_results

    # defining variables
    parent_activity = [act for act in bdb if parent_activity_code in act['code']][0]
    parent_name_act = parent_activity.as_dict()["name"]

    # get list of lcia of all exchanges (incl first row that is the reference exchange)
    df_lcia_exchanges = f_calc_lcia_table_of_exchanges(parent_activity_code, parent_path, parent_am_abs)

    # deleting first row with self-reference
    df_lcia_exchanges=df_lcia_exchanges.loc[~(df_lcia_exchanges["name_exc"]==parent_name_act)]
    # iterate through exchanges and allocate rows to either df_results or df_act_to_be_broken_down
    for count_exc, row in df_lcia_exchanges.iterrows():

        df_dummy = pd.DataFrame(columns=columns_results)
        df_dummy.loc[count_exc] = [row["path"], row["am_abs"], row["lcia_int"], row["lcia_abs"], row["code"]]

        for count_name, name in enumerate(row["path"].split("$")[1:]):
            df_dummy[f"name_l{count_name}"] = name

        if row["database"] == bdb.name:
            df_dummy["done"] = np.nan
            df_act_to_be_broken_down = pd.concat([df_act_to_be_broken_down, df_dummy])
        else:
            df_results = pd.concat([df_results, df_dummy])




def f_calc_lcia_table_of_exchanges(parent_activity_code, parent_path="", parent_am_abs=1, bdb=bdb):
    CC_method = [m for m in bw.methods if 'IPCC 2021 no LT' in str(m) and "climate change no LT" in str(
        m) and 'global warming potential (GWP100)' in str(m)][0]

    ### defining databases
    eidb = bw.Database('ecoinvent 3.9.1_cutoff_ecoSpold02')
    bio = bw.Database('biosphere3')
    #bdb = bw.Database("battery_cell_db_v" + "07")
    dummy_db = Database("dummy_db")



    parent_activity = [act for act in bdb if parent_activity_code in act['code']][0]

    df_dummy = pd.DataFrame(columns=["name_parent_act", "name_exc", "path", "code", "database", "am_abs", "lcia_int", "lcia_abs"])

    parent_name_act= parent_activity.as_dict()["name"]

    bool_last_level_for_parameter_act = ([exc for exc in parent_activity.exchanges()][1].as_dict()["name"] == "Carbon dioxide, fossil") & (len([exc for exc in parent_activity.exchanges()]) == 2)

    for count, exc in enumerate(parent_activity.exchanges()):
        act =  exc.input
        name = exc.input.as_dict()["name"]
        code = exc.input.as_dict()["code"]
        database = exc.input.as_dict()["database"]
        am_rel = exc.as_dict()["amount"]
        am_abs = am_rel*parent_am_abs

        if (exc.as_dict()["type"] == "technosphere") | (exc.as_dict()["type"] == "production"):
            lcia_int = f_calc_lcia(act, CC_method)

        if exc.as_dict()["type"] == "biosphere":
            if "Dummy activity" in [act_it.as_dict()["name"] for act_it in dummy_db]:
                dummy_db.get('dummy_code').delete()

            dummy_act = dummy_db.new_activity(code = 'dummy_code', name = "Dummy activity", unit=exc.input.as_dict()["unit"])
            dummy_act.save()
            dummy_act.new_exchange(input=exc.input.key, amount=1,unit=exc.input.as_dict()["unit"],type="biosphere", database="biosphere3").save()
            dummy_act.save()

            lcia_int = f_calc_lcia(dummy_act, CC_method)
            dummy_db.get('dummy_code').delete()

        lcia_abs = lcia_int*am_abs

        if bool_last_level_for_parameter_act:
            parent_lcia_int = f_calc_lcia(parent_activity, CC_method)
            path=parent_path
            df_dummy.loc[count] = [parent_name_act, name, path, code, database, am_abs, parent_lcia_int, lcia_abs]
        else:
            path=parent_path+"$"+name
            df_dummy.loc[count] = [parent_name_act, name, path, code, database, am_abs, lcia_int, lcia_abs]

    return df_dummy