# -*- encoding: utf-8 -*-
# -----------------------------------------------------------------------------
# @File Name  : fund_service.py
# @Time       : 2021/1/14 下午5:31
# @Author     : X. Peng
# @Email      : acepengxiong@163.com
# @Software   : PyCharm
# -----------------------------------------------------------------------------
from app.service.portfolio_diagnose import *
from app.utils.draw import draw_index_combination_chart


def get_tamp_nav(fund, start_date, rollback=False, invest_type=2):
    """获取基金ID为fund, 起始日期为start_date, 终止日期为当前日期的基金净值表

    Args:
        fund[str]:基金ID
        start_date[date]:起始日期
        rollback[bool]:当起始日期不在净值公布日历中，是否往前取最近的净值公布日
        invest_type[num]:0:公募 1:私募 2:优选

    Returns:df[DataFrame]: 索引为净值公布日， 列为复权净值的净值表; 查询失败则返回None

    """
    with TAMP_SQL(tamp_product_engine) as tamp_product, TAMP_SQL(tamp_fund_engine) as tamp_fund:
        tamp_product_session = tamp_product.session
        tamp_fund_session = tamp_fund.session
        # if invest_type == "private":
        #     sql = "SELECT fund_id, price_date, cumulative_nav FROM fund_nav " \
        #           "WHERE fund_id='{}'".format(fund)
        #     # df = pd.read_sql(sql, con).dropna(how='any')
        #     cur = tamp_product_session.execute(sql)
        if invest_type == 0:
            sql = """select distinct `id`, `end_date`, `accum_nav` from `public_fund_nav` where `id`='{}'  order by `end_date` ASC""".format(
                fund)
            cur = tamp_fund_session.execute(sql)
        elif invest_type == 1:
            sql = """select distinct `fund_id`, `price_date`,`cumulative_nav` from `fund_nav` where `fund_id`='{}'  order by `price_date` ASC""".format(
                fund)
            cur = tamp_fund_session.execute(sql)
        elif invest_type == 2:
            sql = """select distinct `fund_id`,`price_date`,`cumulative_nav` from `fund_nav` where `fund_id`='{}'  order by `price_date` ASC""".format(
                fund)
            cur = tamp_product_session.execute(sql)

        data = cur.fetchall()
        df = pd.DataFrame(data, columns=['fund_id', 'price_date', 'cumulative_nav']).dropna(how='any')
        df.rename({'price_date': 'end_date', 'cumulative_nav': 'adj_nav'}, axis=1, inplace=True)
        df['end_date'] = pd.to_datetime(df['end_date'])

        if rollback and df['end_date'].min() < start_date < df['end_date'].max():
            while start_date not in list(df['end_date']):
                start_date -= datetime.timedelta(days=1)

        df = df[df['end_date'] >= start_date]
        df.drop_duplicates(subset='end_date', inplace=True, keep='first')
        df.set_index('end_date', inplace=True)
        df.sort_index(inplace=True, ascending=True)
    return df


def single_evaluation(fund_id, invest_type=2, index_id='000905.SH'):
    """
       1、该基金整体表现优秀/良好/一般，收益能力优秀/良好/合格/较差，回撤控制能力优秀/良好/合格/较差，风险收益比例较高/一般/较低；
       2、在收益方面，该基金年化收益能力高于/持平/低于同类基金平均水平，有x%区间跑赢大盘/指数，绝对收益能力优秀/一般；
       3、在风险方面，该基金抵御风险能力优秀/良好/一般，在同类基金中处于高/中/低等水平，最大回撤为x%，高于/持平/低于同类基金平均水平；
       4、该基金收益较好/较差的同时回撤较大/较小，也就是说，该基金在用较大/较小风险换取较大/较小收益，存在较高/较低风险；
       5、基金经理，投资年限5.23年，经验丰富；投资能力较强，生涯中共管理过X只基金，历任的X只基金平均业绩在同类中处于上游水平，其中x只排名在前x%；生涯年化回报率x%，同期大盘只有x%；
    :param fund_id: 基金ID
    :param index_id: 指数ID
    :param invest_type: 投资类型：0：公募 1：私募 2：探普优选
    """
    end_date = datetime.datetime(datetime.date.today().year,
                                 datetime.date.today().month, 1) - datetime.timedelta(1)
    start_date = cal_date(end_date, 'Y', 1)

    z_score = search_rank(fund_rank, fund_id, metric='z_score')
    total_level = np.select([z_score >= 80,
                             70 <= z_score < 80,
                             z_score < 70], [0, 1, 2]).item()

    index_return_monthly = get_index_monthly(index_id, start_date)
    fund_nav = get_tamp_nav(fund_id, start_date, invest_type=invest_type)
    fund_nav_monthly = fund_nav.groupby([fund_nav.index.year, fund_nav.index.month]).tail(1)
    fund_nav_monthly = rename_col(fund_nav_monthly, fund_id)
    fund_return_monthly = simple_return(fund_nav_monthly[fund_id].astype(float))
    index_return_monthly.index = index_return_monthly.index.strftime('%Y-%m')
    fund_return_monthly.index = fund_return_monthly.index.strftime('%Y-%m')
    compare = pd.merge(index_return_monthly, fund_return_monthly, how='inner', left_index=True, right_index=True)
    fund_win_rate = ((compare[fund_id] - compare['pct_chg']) > 0).sum() / compare[fund_id].count()

    return_rank = search_rank(fund_rank, fund_id, metric='annual_return_rank')
    return_level = np.select([return_rank >= 0.8,
                              0.7 <= return_rank < 0.8,
                              0.6 <= return_rank < 0.7,
                              return_rank < 0.6], [0, 1, 2, 3]).item()
    return_bool = 1 if return_level > 2 else 0
    return_triple = return_level - 1 if return_level >= 2 else return_level

    drawdown_rank = search_rank(fund_rank, fund_id, metric='max_drawdown_rank')
    drawdown_value = search_rank(fund_rank, fund_id, metric='max_drawdown')
    drawdown_level = np.select([drawdown_rank >= 0.8,
                                0.7 <= drawdown_rank < 0.8,
                                0.6 <= drawdown_rank < 0.7,
                                drawdown_rank < 0.6], [0, 1, 2, 3]).item()
    drawdown_bool = 1 if drawdown_level > 2 else 0
    drawdown_triple = drawdown_level - 1 if drawdown_level >= 2 else drawdown_level

    sharp_rank = search_rank(fund_rank, fund_id, metric='sharp_ratio_rank')
    sharp_level = np.select([sharp_rank >= 0.8,
                             0.6 <= sharp_rank < 0.8,
                             sharp_rank < 0.6], [0, 1, 2]).item()

    data = {1: [total_level, return_level, drawdown_level, sharp_level],
            2: [return_triple, format(fund_win_rate, '.2%'), return_bool],
            3: [drawdown_triple, drawdown_triple, format(drawdown_value, '.2%'), drawdown_triple],
            4: [return_bool, drawdown_bool, drawdown_bool, return_bool, drawdown_bool]}

    x = '30%'
    content = {
        # 第一个评价
        1: [["优秀", "良好", "一般"],
            ["优秀", "良好", "合格", "较差"],
            ["优秀", "良好", "合格", "较差"],
            ["高", "一般", "较低"]],
        # 第二个评价
        2: [["高于", "持平", "低于"],
            x,
            ["优秀", "一般"]],
        # 第三个评价
        3: [["优秀", "良好", "一般"],
            ["高", "中", "低"], x,
            ["高于", "持平", "低于"]],
        # 第四个评价
        4: [["较好", "较差"],
            ["较小", "较大"],
            ["较小", "较小"],
            ["较大", "较小"],
            ["较低", "较高"]]}

    sentence = {
        1: "该基金整体表现%s，收益能力%s，回撤控制能力%s，风险收益比例%s；\n",
        2: "在收益方面，该基金年化收益能力%s同类基金平均水平，有%s区间跑赢指数，绝对收益能力%s；\n",
        3: "在风险方面，该基金抵御风险能力%s，在同类基金中处于%s等水平，最大回撤为%s，%s同类基金平均水平；\n",
        4: "该基金收益%s的同时回撤%s，也就是说，该基金在用%s风险换取%s收益，存在%s风险；\n"}

    ret = []
    fund_name = get_fund_name(fund_id).values[0][0]

    i = 1
    for k, v in data.items():
        single_sentence = str(i) + "、" + sentence[k] % translate_single(content, k, v)
        ret.append(single_sentence)
        i += 1

    evaluation_dict = {'fund_name': fund_name, 'status': '', 'evaluation': ret, 'radar_chart_path': fund_index_compare(fund_id=fund_id, invest_type=invest_type)}

    # if objective:
    #     if fund_id in self.abandon_fund_score + self.abandon_fund_corr:
    #         evaluation_dict['status'] = "换仓"
    #     elif fund_id in self.portfolio:
    #         evaluation_dict['status'] = "保留"
    # else:
    #     evaluation_dict['status'] = ""
    return evaluation_dict


def fund_index_compare(fund_id, invest_type=2, index_id='000905.SH'):
    start_date = datetime.datetime(2000, 1, 1)
    index_daily = get_index_daily(index_id, start_date)
    fund_nav = get_tamp_nav(fund_id, start_date, invest_type=invest_type)
    fund_nav = rename_col(fund_nav, fund_id)
    compare = pd.merge(index_daily, fund_nav, how='inner', left_index=True, right_index=True)
    compare[index_id + '_return_ratio'] = (compare[index_id] / compare[index_id].iloc[0] - 1) * 100
    compare[fund_id + '_return_ratio'] = (compare[fund_id] / compare[fund_id].iloc[0] - 1) * 100

    xlabels = ["" for i in range(len(compare))]

    index_name = get_index_name(index_id).values[0][0]
    chart_data = {
        "xlabels": xlabels,
        "index": {'name': index_name, 'data': compare[index_id + "_return_ratio"].values},
        "fund": {'name': fund_id, 'data': compare[fund_id + "_return_ratio"].values},
    }
    r = draw_index_combination_chart(chart_data)
    return r


if __name__ == '__main__':
    print(single_evaluation(fund_id='HF00005AFK'))