#!/usr/bin/python3.6
# -*- coding: utf-8 -*-
# @Time    : 2020/11/23 15:29
# @Author  : Jie. Z
# @Email   : zhaojiestudy@163.com
# @File    : result_service.py
# @Software: PyCharm

import pandas as pd
import numpy as np
import datetime
from decimal import Decimal
from app.service.data_service import UserCustomerDataAdaptor
from app.utils.week_evaluation import *


def resample(df, trading_cal, freq):
    """对基金净值表进行粒度不同的重采样,并剔除不在交易日中的结果

    Args:
        df ([DataFrame]): [原始基金净值表]
        trading_cal ([type]): [上交所交易日表]
        freq ([type]): [重采样频率: 1:工作日,2:周, 3:月, 4:半月, 5:季度]

    Returns:
        [DataFrame]: [重采样后剔除不在交易日历中的净值表和交易日历以净值日期为索引的合表]
    """
    freq_dict = {1: 'B', 2: 'W-FRI', 3: 'M', 4: 'SM', 5: 'Q'}
    resample_freq = freq_dict[freq]
    # 按采样频率进行重采样并进行净值的前向填充
    df = df.resample(rule=resample_freq).ffill()

    # 根据采样频率确定最大日期偏移量(保证偏移后的日期与重采样的日期在同一周,同一月,同一季度等)
    timeoffset_dict = {1: 1, 2: 5, 3: 30, 4: 15, 5: 120}
    timeoffetmax = timeoffset_dict[freq]

    # Dataframe不允许直接修改index,新建一份index的复制并转为list
    new_index = list(df.index)
    # 遍历重采样后的日期
    for idx, date in enumerate(df.index):
        # 如果重采样后的日期不在交易日历中
        if date not in trading_cal.index:
            # 对重采样后的日期进行偏移
            for time_offset in range(1, timeoffetmax):
                # 如果偏移后的日期在交易日历中,保留偏移后的日期
                if date - datetime.timedelta(days=time_offset) in trading_cal.index:
                    new_index[idx] = date - datetime.timedelta(days=time_offset)
                    # 任意一天满足立即退出循环
                    break

    # 更改净值表的日期索引为重采样后且在交易日内的日期
    df.index = pd.Series(new_index)
    return df


class UserCustomerResultAdaptor(UserCustomerDataAdaptor):
    total_result_data = {}
    group_result_data = []

    def __init__(self, user_id, customer_id, end_date=str(datetime.date.today())):
        # super().__init__()
        super().__init__(user_id, customer_id, end_date)

    # 综述数据
    def get_total_data(self):

        for folio in self.group_data.keys():
            # self.group_result_data.append({folio: {}})
            cur_folio_result_cnav_data = self.group_data[folio]["result_cnav_data"]
            cur_folio_order_data = self.group_data[folio]["order_df"]

            fund_id_list = list(cur_folio_order_data["fund_id"].unique())
            fund_id_list_earn = [i + "_earn" for i in fund_id_list]
            fund_id_list_amount = [i + "_amount" for i in fund_id_list]
            profit_df = cur_folio_result_cnav_data[fund_id_list_earn]

            resample_df = resample(cur_folio_result_cnav_data, self.trade_cal, 2)

            # 组合收益率
            return_ratio_serise = self.combination_yield(cur_folio_result_cnav_data, fund_id_list)

            # 总成本
            total_cost = float(cur_folio_order_data[cur_folio_order_data["order_type"] == 1]["confirm_amount"].sum() - \
                         cur_folio_order_data[cur_folio_order_data["order_type"] == 2]["confirm_amount"].sum())
            # 累积盈利
            cumulative_profit = profit_df.sum().sum()
            # 年化收益
            return_ratio_year = 0
            """*************************年化收益*******************************"""
            # 期末资产
            ending_assets = cumulative_profit + total_cost

            # 本月收益
            cur_month_profit_df = profit_df.loc[self.month_start_date:self.end_date+datetime.timedelta(days=1), fund_id_list_earn]
            cur_month_profit = cur_month_profit_df.sum().sum()
            # 本月累积收益率
            cur_month_profit_ratio = return_ratio_serise.loc[self.month_start_date:].sum()

            # 今年累积收益
            cur_year_date = pd.to_datetime(str(datetime.date(year=self.end_date.year, month=1, day=1)))
            cur_year_profit_df = profit_df.loc[cur_year_date:self.end_date + datetime.timedelta(days=1), fund_id_list_earn]
            cur_year_profit = cur_year_profit_df.sum().sum()
            # 今年累积收益率
            cur_year_profit_ratio = return_ratio_serise.loc[cur_year_date:]

            # 月度回报
            def year_month(x):
                a = x.year
                b = x.month
                return str(a) + "/" + str(b)
            profit_df_cp = profit_df.copy()
            profit_df_cp["date"] = profit_df_cp.index
            grouped = profit_df_cp.groupby(profit_df_cp["date"].apply(year_month))
            sum_group = grouped.agg(np.sum)
            month_sum = sum_group.sum(axis=1)

            # 累积收益率
            profit_df_cp["cumulative_return"] = return_ratio_serise.cumsum()
            grouped_cumulative = profit_df_cp["cumulative_return"].groupby(profit_df_cp["date"].apply(year_month))
            month_cumulative_return = grouped_cumulative.last()

    # 单个组合基金净值数据
    def signal_fund_info_data(self, p_fund_id_list, p_order_df):
        pass
        # 组合数据

    def get_group_data(self):
        pass

    def performance_reward(self, order_info, ):
        pass

    @staticmethod
    def combination_yield(p_combina_df, fund_id_list):
        fund_id_list_amount = [i + "_amount" for i in fund_id_list]
        fund_id_list_profit_ratio = [i + "_profit_ratio" for i in fund_id_list]
        nav_amount_df = p_combina_df[fund_id_list + fund_id_list_amount+fund_id_list_profit_ratio].copy()

        nav_amount_df["sum_amount"] = nav_amount_df[fund_id_list_amount].sum(axis=1).apply(lambda x: Decimal.from_float(x))
        for amount_name in fund_id_list:
            nav_amount_df[amount_name+"_amount_ratio"] = nav_amount_df[amount_name+"_amount"]/nav_amount_df["sum_amount"]
            nav_amount_df[amount_name+"_profit_ratio_weight"] = nav_amount_df[amount_name+"_amount_ratio"] * nav_amount_df[amount_name+"_profit_ratio"]

        fund_id_list_profit_ratio_weight = [i + "_profit_ratio_weight" for i in fund_id_list]
        nav_profit_ratio_weight = nav_amount_df[fund_id_list_profit_ratio_weight].copy().fillna(method='ffill')

        # 收益率
        return_ratio = nav_profit_ratio_weight.sum(axis=1)
        return return_ratio