from base_class import BaseVariableFunction
from base_class import *
baseclass = BaseVariableFunction(__file__)
baseclass.makedirpath(baseclass.dalao_profit_st_solscan_path)
baseclass.makedirpath(baseclass.dalao_ana_solscan_path)

baseclass.makedirpath(baseclass.dalao_total_ana_solscan_path)


baseclass.open_base_library()
decimal.getcontext().prec = 100
old_print = print


def timestamped_print(*args, **kwargs):
    old_print(datetime.datetime.utcnow().replace(
        microsecond=0), *args, **kwargs)


print = timestamped_print
print('\n'*5)
print(f"{'{:<6}'.format('ENTER')} {baseclass.scriptfilename} ----------------NOTE-----------NOTE---------------")


TotalAnalysis_columns = [
    "add",
    # "whichcontract",
    "beizhu",

    "03d_cost",
    "03d_earn",
    "03d_earnper",
    "03d_difcost",
    "03d_difearn",
    "03d_difper",
    "03d_costmedian",
    "03d_costmean",
    "03d_earncount_per",
    "03d_cost_dropaddouttoken",
    "03d_earn_dropaddouttoken",
    "03d_earnper_dropaddouttoken",
    "03d_difcost_dropaddouttoken",
    "03d_difearn_dropaddouttoken",
    "03d_difper_dropaddouttoken",
    "03d_costmedian_dropaddouttoken",
    "03d_costmean_dropaddouttoken",
    "03d_earncount_per_dropaddouttoken",
    "03d_trans",


    "07d_cost",
    "07d_earn",
    "07d_earnper",
    "07d_difcost",
    "07d_difearn",
    "07d_difper",
    "07d_costmedian",
    "07d_costmean",
    "07d_earncount_per",
    "07d_cost_dropaddouttoken",
    "07d_earn_dropaddouttoken",
    "07d_earnper_dropaddouttoken",
    "07d_difcost_dropaddouttoken",
    "07d_difearn_dropaddouttoken",
    "07d_difper_dropaddouttoken",
    "07d_costmedian_dropaddouttoken",
    "07d_costmean_dropaddouttoken",
    "07d_earncount_per_dropaddouttoken",
    "07d_trans",


    "11d_cost",
    "11d_earn",
    "11d_earnper",
    "11d_difcost",
    "11d_difearn",
    "11d_difper",
    "11d_costmedian",
    "11d_costmean",
    "11d_earncount_per",
    "11d_cost_dropaddouttoken",
    "11d_earn_dropaddouttoken",
    "11d_earnper_dropaddouttoken",
    "11d_difcost_dropaddouttoken",
    "11d_difearn_dropaddouttoken",
    "11d_difper_dropaddouttoken",
    "11d_costmedian_dropaddouttoken",
    "11d_costmean_dropaddouttoken",
    "11d_earncount_per_dropaddouttoken",
    "11d_trans",


    "15d_cost",
    "15d_earn",
    "15d_earnper",
    "15d_difcost",
    "15d_difearn",
    "15d_difper",
    "15d_costmedian",
    "15d_costmean",
    "15d_earncount_per",
    "15d_cost_dropaddouttoken",
    "15d_earn_dropaddouttoken",
    "15d_earnper_dropaddouttoken",
    "15d_difcost_dropaddouttoken",
    "15d_difearn_dropaddouttoken",
    "15d_difper_dropaddouttoken",
    "15d_costmedian_dropaddouttoken",
    "15d_costmean_dropaddouttoken",
    "15d_earncount_per_dropaddouttoken",
    "15d_trans",

    "15dearn_dif"
]


def get_tokenswap_amount(df):
    def get_cost(gdf):
        token_amount_list = gdf['swap_token_amount'].to_list()

        arr_out_token_amount = [abs(decimal.Decimal(
            token_amount)) for token_amount in token_amount_list if decimal.Decimal(token_amount) < 0]
        arr_in_token_amount = [decimal.Decimal(
            token_amount) for token_amount in token_amount_list if decimal.Decimal(token_amount) > 0]
        buy_counts = len(arr_in_token_amount)
        sell_counts = len(arr_out_token_amount)

        out_token_amount = sum(arr_out_token_amount)
        in_token_amount = sum(arr_in_token_amount)

        out_token_amount_str = '{0:.2f}'.format(out_token_amount)
        in_token_amount_str = '{0:.2f}'.format(in_token_amount)
        outtoken_per = '{0:.2f}'.format(
            out_token_amount/in_token_amount) if in_token_amount != 0 else '-10'
        gdf[['buy_counts', 'sell_counts', 'intoken_amount', 'outtoken_amount', 'outtoken_per']] = [buy_counts, sell_counts,
                                                                                                   in_token_amount_str, out_token_amount_str, outtoken_per]
        return gdf
    df[['buy_counts', 'sell_counts', 'intoken_amount',
        'outtoken_amount', 'outtoken_per']] = [0, 0, '0', '0', '0']
    df = df.groupby(["token_idx"], group_keys=False).apply(
        lambda gdf:  get_cost(gdf))
    df = df.reset_index(drop=True)
    return df


def get_sol_profit(df):
    # 計算利潤
    df['cost_main'] = 0
    df['earn_main'] = 0
    df['earn_percent'] = -10
    df = df.astype({'swap_eth_amount': float})
    costMain_df = (
        df
        .groupby('token_idx')["swap_eth_amount"]
        .apply(lambda x: abs(x[x < 0].sum()))
    )
    df['cost_main'] = df['token_idx'].map(costMain_df)

    df.loc[df['outtoken_per'] == "-10", "cost_main"] = 0
    earnMain_df = (
        df
        .groupby('token_idx')["swap_eth_amount"]
        .sum()
    )
    df['earn_main'] = df["token_idx"].map(earnMain_df)
    df['earn_percent'] = np.where(
        df['cost_main'] != 0,
        df['earn_main'] / df['cost_main'],
        -10,
    )
    return df


def analysis_lastdays(df, now_unix_time, intervaldays=30):
    if len(df) == 0:
        return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    # need consider df may null if use iloc
    lastdf = df[df["TokenFirstTime"] >= now_unix_time - 3600*24*intervaldays]
    # 去除那些earnper为-10的
    lastdf = lastdf[lastdf['cost_main'] != 0]
    # 去除 cost_main 过小的 <0.04  sol 理论上 同时fir_cost_main!=0
    lastdf = lastdf[lastdf['cost_main'] >= 0.04] 
    lastdf = lastdf[lastdf['fir_cost_main'] != 0]
    lastdf = lastdf.reset_index(drop=True)
    if len(lastdf) == 0:
        return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    last_cost_sum = lastdf['cost_main'].sum()
    last_earn_sum = lastdf['earn_main'].sum()
    last_cost_median = lastdf['cost_main'].median()
    last_cost_mean = lastdf['cost_main'].mean()
    last_earnper = last_earn_sum / last_cost_sum if last_cost_sum != 0 else -10
    last_trans_amount = len(lastdf)
    lastdf['earn_percent'] = np.where(
        lastdf['cost_main'] != 0,
        lastdf['earn_main'] / lastdf['cost_main'],
        -10,
    )
    last_earncount_per = (len(lastdf[(
        lastdf['earn_percent'] >= 0.05)]) / len(lastdf) if len(lastdf) != 0 else 0)
    earnmain_max = lastdf['earn_main'].max()
    last_earn_difmax_sum = last_earn_sum - earnmain_max
    last_cost_difmax_sum = last_cost_sum - \
        lastdf[lastdf['earn_main'] == earnmain_max]['cost_main'].to_list()[0]
    last_dif_earnper = (
        last_earn_difmax_sum / last_cost_difmax_sum if last_cost_difmax_sum != 0 else -10
    )
    return (
        last_cost_sum,
        last_earn_sum,
        last_earnper,
        last_cost_difmax_sum,
        last_earn_difmax_sum,
        last_dif_earnper,
        last_cost_median,
        last_cost_mean,
        last_earncount_per,
        last_trans_amount
    )


def analysis_lastdays_dropaddouttoken(df, now_unix_time, intervaldays=30):
    if len(df) == 0:
        return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    # need consider df may null if use iloc
    lastdf = df[df["TokenFirstTime"] >= now_unix_time - 3600*24*intervaldays]
    # 去除那些earnper为-10的
    lastdf = lastdf[lastdf['cost_main'] != 0]
    # 去除 cost_main 过小的 <0.04  sol 理论上 同时fir_cost_main!=0
    lastdf = lastdf[lastdf['cost_main'] >= 0.04] 
    lastdf = lastdf[lastdf['fir_cost_main'] != 0]
    lastdf = lastdf.reset_index(drop=True)
    if len(lastdf) == 0:
        return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    last_cost_sum = lastdf['cost_main'].sum()
    last_earn_sum = lastdf["earn_main_dropaddouttoken"].sum()
    last_cost_median = lastdf['cost_main'].median()
    last_cost_mean = lastdf['cost_main'].mean()
    last_earnper = last_earn_sum / last_cost_sum if last_cost_sum != 0 else -10
    last_trans_amount = len(lastdf)
    lastdf['earn_percent'] = np.where(
        lastdf['cost_main'] != 0,
        lastdf["earn_main_dropaddouttoken"] / lastdf['cost_main'],
        -10,
    )
    last_earncount_per = (len(lastdf[(
        lastdf['earn_percent'] >= 0.05)]) / len(lastdf) if len(lastdf) != 0 else 0)
    earnmain_max = lastdf["earn_main_dropaddouttoken"].max()
    last_earn_difmax_sum = last_earn_sum - earnmain_max
    last_cost_difmax_sum = last_cost_sum - \
        lastdf[lastdf['earn_main_dropaddouttoken'] == earnmain_max]['cost_main'].to_list()[
            0]
    last_dif_earnper = (
        last_earn_difmax_sum / last_cost_difmax_sum if last_cost_difmax_sum != 0 else -10
    )
    return (
        last_cost_sum,
        last_earn_sum,
        last_earnper,
        last_cost_difmax_sum,
        last_earn_difmax_sum,
        last_dif_earnper,
        last_cost_median,
        last_cost_mean,
        last_earncount_per,
        last_trans_amount
    )


onedalao_ana_columns = ['TokenFirstTime', 'swap_tokenaddress', 'swap_tokenname', 'buy_counts', 'sell_counts',
                        'outtoken_per', 'cost_main', 'earn_main', 'earn_percent']


def get_analyres(df,  dalao_address, now_unix_time):

    (last_03d_cost, last_03d_earn, last_03d_earnper, last_03d_difcost, last_03d_difearn, last_03d_difper, last_03d_costmedian, last_03d_costmean, last_03d_earncount_per, last_03d_trans) = analysis_lastdays(
        df, now_unix_time=now_unix_time, intervaldays=3
    )
    (last_07d_cost, last_07d_earn, last_07d_earnper, last_07d_difcost, last_07d_difearn, last_07d_difper, last_07d_costmedian, last_07d_costmean, last_07d_earncount_per, last_07d_trans) = analysis_lastdays(
        df, now_unix_time=now_unix_time, intervaldays=7
    )
    (last_11d_cost, last_11d_earn, last_11d_earnper, last_11d_difcost, last_11d_difearn, last_11d_difper, last_11d_costmedian, last_11d_costmean, last_11d_earncount_per, last_11d_trans) = analysis_lastdays(
        df, now_unix_time=now_unix_time, intervaldays=11
    )
    (last_15d_cost, last_15d_earn, last_15d_earnper, last_15d_difcost, last_15d_difearn, last_15d_difper, last_15d_costmedian, last_15d_costmean, last_15d_earncount_per, last_15d_trans) = analysis_lastdays(
        df, now_unix_time=now_unix_time, intervaldays=15
    )
    # # 去除所有daxin
    # df = df[df["isdaxin"] == "0"].reset_index(drop=True)

    (last_03d_cost_dropaddouttoken, last_03d_earn_dropaddouttoken, last_03d_earnper_dropaddouttoken, last_03d_difcost_dropaddouttoken, last_03d_difearn_dropaddouttoken, last_03d_difper_dropaddouttoken, last_03d_costmedian_dropaddouttoken, last_03d_costmean_dropaddouttoken, last_03d_earncount_per_dropaddouttoken, last_03d_trans) = analysis_lastdays_dropaddouttoken(
        df, now_unix_time=now_unix_time, intervaldays=3
    )
    (last_07d_cost_dropaddouttoken, last_07d_earn_dropaddouttoken, last_07d_earnper_dropaddouttoken, last_07d_difcost_dropaddouttoken, last_07d_difearn_dropaddouttoken, last_07d_difper_dropaddouttoken, last_07d_costmedian_dropaddouttoken, last_07d_costmean_dropaddouttoken, last_07d_earncount_per_dropaddouttoken, last_07d_trans) = analysis_lastdays_dropaddouttoken(
        df, now_unix_time=now_unix_time, intervaldays=7
    )
    (last_11d_cost_dropaddouttoken, last_11d_earn_dropaddouttoken, last_11d_earnper_dropaddouttoken, last_11d_difcost_dropaddouttoken, last_11d_difearn_dropaddouttoken, last_11d_difper_dropaddouttoken, last_11d_costmedian_dropaddouttoken, last_11d_costmean_dropaddouttoken, last_11d_earncount_per_dropaddouttoken, last_11d_trans) = analysis_lastdays_dropaddouttoken(
        df, now_unix_time=now_unix_time, intervaldays=11
    )
    (last_15d_cost_dropaddouttoken, last_15d_earn_dropaddouttoken, last_15d_earnper_dropaddouttoken, last_15d_difcost_dropaddouttoken, last_15d_difearn_dropaddouttoken, last_15d_difper_dropaddouttoken, last_15d_costmedian_dropaddouttoken, last_15d_costmean_dropaddouttoken, last_15d_earncount_per_dropaddouttoken, last_15d_trans) = analysis_lastdays_dropaddouttoken(
        df, now_unix_time=now_unix_time, intervaldays=15
    )
    analist = [
        dalao_address,
        "",
        last_03d_cost,
        last_03d_earn,
        last_03d_earnper,
        last_03d_difcost,
        last_03d_difearn,
        last_03d_difper,
        last_03d_costmedian,
        last_03d_costmean,
        last_03d_earncount_per,
        last_03d_cost_dropaddouttoken,
        last_03d_earn_dropaddouttoken,
        last_03d_earnper_dropaddouttoken,
        last_03d_difcost_dropaddouttoken,
        last_03d_difearn_dropaddouttoken,
        last_03d_difper_dropaddouttoken,
        last_03d_costmedian_dropaddouttoken,
        last_03d_costmean_dropaddouttoken,
        last_03d_earncount_per_dropaddouttoken,
        last_03d_trans,

        last_07d_cost,
        last_07d_earn,
        last_07d_earnper,
        last_07d_difcost,
        last_07d_difearn,
        last_07d_difper,
        last_07d_costmedian,
        last_07d_costmean,
        last_07d_earncount_per,
        last_07d_cost_dropaddouttoken,
        last_07d_earn_dropaddouttoken,
        last_07d_earnper_dropaddouttoken,
        last_07d_difcost_dropaddouttoken,
        last_07d_difearn_dropaddouttoken,
        last_07d_difper_dropaddouttoken,
        last_07d_costmedian_dropaddouttoken,
        last_07d_costmean_dropaddouttoken,
        last_07d_earncount_per_dropaddouttoken,
        last_07d_trans,

        last_11d_cost,
        last_11d_earn,
        last_11d_earnper,
        last_11d_difcost,
        last_11d_difearn,
        last_11d_difper,
        last_11d_costmedian,
        last_11d_costmean,
        last_11d_earncount_per,
        last_11d_cost_dropaddouttoken,
        last_11d_earn_dropaddouttoken,
        last_11d_earnper_dropaddouttoken,
        last_11d_difcost_dropaddouttoken,
        last_11d_difearn_dropaddouttoken,
        last_11d_difper_dropaddouttoken,
        last_11d_costmedian_dropaddouttoken,
        last_11d_costmean_dropaddouttoken,
        last_11d_earncount_per_dropaddouttoken,
        last_11d_trans,

        last_15d_cost,
        last_15d_earn,
        last_15d_earnper,
        last_15d_difcost,
        last_15d_difearn,
        last_15d_difper,
        last_15d_costmedian,
        last_15d_costmean,
        last_15d_earncount_per,
        last_15d_cost_dropaddouttoken,
        last_15d_earn_dropaddouttoken,
        last_15d_earnper_dropaddouttoken,
        last_15d_difcost_dropaddouttoken,
        last_15d_difearn_dropaddouttoken,
        last_15d_difper_dropaddouttoken,
        last_15d_costmedian_dropaddouttoken,
        last_15d_costmean_dropaddouttoken,
        last_15d_earncount_per_dropaddouttoken,
        last_15d_trans,

        last_15d_earn-last_15d_earn_dropaddouttoken
    ]

    global TotalAnalysis_list
    TotalAnalysis_list.append(analist)


def calute_days(df, now_unix_time):
    df["diffdays"] = 0
    intervaldays_list = [15, 11, 7, 3]
    for intervaldays in intervaldays_list:
        df.loc[df["TokenFirstTime"] >=
               now_unix_time - 3600*24*intervaldays, "diffdays"] = intervaldays
    return df


def calucate_earnmain_dropoutoken(row):
    earnmain_amount_dropoutoken = decimal.Decimal(row['earn_main'])
    outtoken_per = decimal.Decimal(row["outtoken_per"])
    if outtoken_per >= 1.2 or outtoken_per == -10:
        earnmain_amount_dropoutoken = decimal.Decimal(0)
    earnmain_amount_dropoutoken_str = '{0:.4f}'.format(
        earnmain_amount_dropoutoken)
    return float(earnmain_amount_dropoutoken_str)


def makeDexurl(row, dalao_address):
    tokenAddress = row['swap_tokenaddress']
    urlname = f"https://dexscreener.com/solana/{tokenAddress}?maker={dalao_address}"
    return '=HYPERLINK("{}","{}")'.format(urlname, "DEX/"+tokenAddress)


def get_ana_df(dalao_address, df, success_address_list):
    onedalao_ana_df = df[onedalao_ana_columns].drop_duplicates(
    ).reset_index(drop=True)
    onedalao_ana_df.insert(
        loc=2, column="swap_tokenadd_dexurl", value="")

    # def makeDexurl(row, dalao_address):
    #     tokenAddress = row['swap_tokenaddress']
    #     urlname = f"https://dexscreener.com/solana/{tokenAddress}?maker={dalao_address}"
    #     return '=HYPERLINK("{}","{}")'.format(urlname, "DEX/"+tokenAddress)
    # https://dexscreener.com/bsc/0xd57e3a71e95a088cd3ac63047fc1ef845f7bbac1
    onedalao_ana_df['swap_tokenadd_dexurl'] = onedalao_ana_df.apply(
        lambda row: makeDexurl(row, dalao_address), axis=1)

    # def calucate_earnmain_dropoutoken(row):
    #     earnmain_amount_dropoutoken = decimal.Decimal(row['earn_main'])
    #     outtoken_per = decimal.Decimal(row["outtoken_per"])
    #     if outtoken_per >= 1.2 or outtoken_per == -10:
    #         earnmain_amount_dropoutoken = decimal.Decimal(0)
    #     earnmain_amount_dropoutoken_str = '{0:.4f}'.format(
    #         earnmain_amount_dropoutoken)
    #     return float(earnmain_amount_dropoutoken_str)

    # 如果outoken超了，earn_main_dropaddouttoken 的值有两种处理方式
    # 一种设置为0 即为不亏不赚
    # 一种为全负  即为全亏了
    onedalao_ana_df["earn_main_dropaddouttoken"] = onedalao_ana_df.apply(
        lambda row: calucate_earnmain_dropoutoken(row), axis=1)
    now_unix_time = int(time.time())

    get_analyres(df=onedalao_ana_df, dalao_address=dalao_address,
                 now_unix_time=now_unix_time)

    onedalao_ana_df = calute_days(
        df=onedalao_ana_df, now_unix_time=now_unix_time)
    onedalao_ana_df['TokenFirstTime'] = pd.to_datetime(
        onedalao_ana_df['TokenFirstTime'], unit='s')

    handle_onedalao_ana_df = onedalao_ana_df[onedalao_ana_df['cost_main'] != 0].reset_index(
        drop=True)

    baseclass.makedirpath(baseclass.dalao_ana_solscan_path / dalao_address)

    onedalao_ana_df.to_csv(baseclass.dalao_ana_solscan_path /
                           dalao_address/f"analysisprofit_{dalao_address}.csv", index=False)
    handle_onedalao_ana_df.to_csv(baseclass.dalao_ana_solscan_path /
                                  dalao_address/f"analysisprofit_handle_{dalao_address}.csv", index=False)
    success_address_list.remove(dalao_address)
    # print(f"{dalao_address} success remainder= {len(success_address_list)} \n", end='')


def get_profit_st(str_dalao_address):

    df = pd.read_csv(baseclass.dalao_config_st_solscan_path /
                     f"configtoken_{str_dalao_address}.csv", dtype=object)
#    txhash	date	timestamp	action	from	in_tokenaddress	out_tokenaddress	in_tokenname	out_tokenname	in_tokenamount	out_tokenamount	router	israydium	swap_tokenaddress	swap_eth_amount	swap_token_amount	token_idx

    df["timestamp"] = df["timestamp"].astype(int)

    df["TokenFirstTime"] = df.groupby("token_idx")[
        "timestamp"].transform("min")
    df = get_tokenswap_amount(df=df)
    df = get_sol_profit(df=df)
    df = df.sort_values(by=['TokenFirstTime', 'token_idx'], ascending=[
        False, True]).reset_index(drop=True)
    profit_df = df.drop(columns=['TokenFirstTime'])
    profit_df.to_csv(baseclass.dalao_profit_st_solscan_path /
                     f"profit_st_{str_dalao_address}.csv", index=False)

    return df


def get_dalaoaddress_list():
    df = pd.read_csv(baseclass.dalao_merge_path /
                     "filter_dalao.csv", dtype=object)
    arr_dalao_address = df["dalaoAddress"].tolist()
    return arr_dalao_address


def save_total_ana_df():
    global TotalAnalysis_list
    TotalAnalysis_df = pd.DataFrame(
        data=TotalAnalysis_list, columns=TotalAnalysis_columns
    )

    TotalAnalysis_df = TotalAnalysis_df.round(4)
    TotalAnalysis_df = TotalAnalysis_df.sort_values(by=["add"], ascending=[
        True]).reset_index(drop=True)

    TotalAnalysis_df.to_csv(
        baseclass.dalao_total_ana_solscan_path/f"totalana.csv", index=False)

    TotalAnalysis_df.to_excel(
        baseclass.dalao_total_ana_solscan_path/f"totalana.xlsx", index=False)
    addtion_filter_mask = (
        (TotalAnalysis_df["15d_difearn"] >=
         0.9*TotalAnalysis_df["11d_difearn"])
        & (TotalAnalysis_df["11d_difearn"] >= 0.9*TotalAnalysis_df["07d_difearn"])
        & (TotalAnalysis_df["07d_difearn"] >= 0.9*TotalAnalysis_df["03d_difearn"])
    )
    new_TotalAnalysis_df = TotalAnalysis_df[addtion_filter_mask].reset_index(
        drop=True)
    new_TotalAnalysis_df.to_excel(
        baseclass.dalao_total_ana_solscan_path/f"increase_totalana.xlsx", index=False)


def main():
    dalao_address_list = get_dalaoaddress_list()
    for dalao_address in dalao_address_list:
        print(f"enter {dalao_address}")
        if not (baseclass.dalao_config_st_solscan_path /
                f"configtoken_{dalao_address}.csv").exists():
            continue
        df = get_profit_st(str_dalao_address=dalao_address)
        get_ana_df(dalao_address=dalao_address, df=df)
    save_total_ana_df()
    return


TotalAnalysis_list = []
main()


print(f"{'{:<6}'.format('END')} {baseclass.scriptfilename} ----------------NOTE-----------NOTE---------------")
