import pandas as pd
from python.fund.db.database import RawDatabaseConnector, BasicDatabaseConnector, DerivedDatabaseConnector
from python.fund.db.view_models import FundDailyCollection
from python.fund.db.raw_models import RqFundIndicator
from python.fund.db.basic_models import FundNav, FundInfo, FundRatingLatest, FundSize
from python.fund.db.derived_models import FundAlpha, FundScore, FundIndicator
from sqlalchemy import create_engine
from api_investment.constants import ExchangeStatus


def get_fund_df():
    with BasicDatabaseConnector().managed_session() as mn_session:
        try:
            query = mn_session.query(
                FundInfo.fund_id,
                FundInfo.order_book_id,
                FundInfo.wind_class_1,
                FundInfo.start_date,
                FundInfo.manager_id,
                FundInfo.company_id,
                FundInfo.benchmark,
                FundInfo.desc_name,
                FundInfo.track_index,
            )
            funds = pd.read_sql(query.statement, query.session.bind)
            return funds.set_index('fund_id')
        except Exception as e:
            print('Failed fill get data <err_msg> {}'.format(e))

def get_nav_df():
    with BasicDatabaseConnector().managed_session() as mn_session:
        try:
            latest_time = mn_session.query(FundNav).order_by(FundNav.datetime.desc()).limit(1).one_or_none()
            latest_time = latest_time.datetime
            query = mn_session.query(
                FundNav.fund_id,
                FundNav.unit_net_value,
                FundNav.acc_net_value,
                FundNav.adjusted_net_value,
                FundNav.datetime,
                FundNav.redeem_status,
                FundNav.subscribe_status,
            ).filter(FundNav.datetime==latest_time)

            nav = pd.read_sql(query.statement, query.session.bind)
            return nav.set_index('fund_id'), latest_time
        except Exception as e:
            print('Failed fill get data <err_msg> {}'.format(e))

def get_indicator_df():
    with RawDatabaseConnector().managed_session() as quant_session:
        try:
            latest_time = quant_session.query(RqFundIndicator).order_by(RqFundIndicator.datetime.desc()).limit(1).one_or_none()
            latest_time = latest_time.datetime
            query = quant_session.query(
                RqFundIndicator.order_book_id,
                RqFundIndicator.annualized_returns,
                RqFundIndicator.annualized_risk,
                RqFundIndicator.average_size,
                RqFundIndicator.information_ratio,
                RqFundIndicator.last_month_return,
                RqFundIndicator.last_six_month_return,
                RqFundIndicator.last_three_month_return,
                RqFundIndicator.last_twelve_month_return,
                RqFundIndicator.last_week_return,
                RqFundIndicator.year_to_date_return,
                RqFundIndicator.to_date_return,
                RqFundIndicator.sharp_ratio,
                RqFundIndicator.max_drop_down,
            ).filter(RqFundIndicator.datetime==latest_time)
            indicator = pd.read_sql(query.statement, query.session.bind)
            return indicator

        except Exception as e:
            print('Failed fill get data <err_msg> {}'.format(e))

def get_institution_rating_df():
    with BasicDatabaseConnector().managed_session() as mn_session:
        try:
            latest_time = mn_session.query(FundRatingLatest).order_by(FundRatingLatest.update_time.desc()).limit(1).one_or_none()
            latest_time = latest_time.update_time
            print(latest_time)
            query = mn_session.query(
                FundRatingLatest.fund_id,
                FundRatingLatest.zs,
                FundRatingLatest.sh3,
                FundRatingLatest.sh5,
                FundRatingLatest.jajx,
            ).filter(FundRatingLatest.update_time==latest_time)
            rating = pd.read_sql(query.statement, query.session.bind)
            return rating

        except Exception as e:
            print('Failed fill get data <err_msg> {}'.format(e))

def get_size_df():
    with BasicDatabaseConnector().managed_session() as mn_session:
        try:
            query = mn_session.query(
                FundSize.fund_id,
                FundSize.latest_size
            )
            df = pd.read_sql(query.statement, query.session.bind)
            df = df.drop_duplicates(subset=['fund_id'], keep='last')
            df = df.set_index('fund_id')
            return df
        except Exception as e:
            print('Failed fill get data <err_msg> {}'.format(e))

def get_alpha_df():
    with DerivedDatabaseConnector().managed_session() as mn_session:
        try:
            latest_time = mn_session.query(FundAlpha).order_by(FundAlpha.datetime.desc()).limit(1).one_or_none()
            latest_time = latest_time.datetime
            print(latest_time)
            query = mn_session.query(
                FundAlpha.fund_id,
                FundAlpha.track_err,
                FundAlpha.this_y_alpha,
                FundAlpha.cumulative_alpha,
                FundAlpha.w1_alpha,
                FundAlpha.m1_alpha,
                FundAlpha.m3_alpha,
                FundAlpha.m6_alpha,
                FundAlpha.y1_alpha,
                FundAlpha.y3_alpha,
                FundAlpha.y5_alpha,
                FundAlpha.y10_alpha,
            ).filter(FundAlpha.datetime==latest_time)
            df = pd.read_sql(query.statement, query.session.bind)
            df = df.drop_duplicates(subset=['fund_id'], keep='last')
            return df

        except Exception as e:
            print('Failed fill get data <err_msg> {}'.format(e))

def get_score_df():
    with DerivedDatabaseConnector().managed_session() as mn_session:
        try:
            latest_time = mn_session.query(FundScore.datetime).order_by(FundScore.datetime.desc()).limit(1).one_or_none()[0]
            print(latest_time)
            query = mn_session.query(
                FundScore.fund_id,
                FundScore.tag_name,
                FundScore.score,
            ).filter(FundScore.datetime==latest_time)
            df = pd.read_sql(query.statement, query.session.bind)
            df = df.drop_duplicates(subset=['fund_id'], keep='last')
            return df

        except Exception as e:
            print('Failed get_score_df <err_msg> {}'.format(e))

def get_tag_fund_indicator_df():
    with DerivedDatabaseConnector().managed_session() as mn_session:
        try:
            latest_time = mn_session.query(FundIndicator).order_by(FundIndicator.datetime.desc()).limit(1).one_or_none()
            latest_time = latest_time.datetime
            print(latest_time)
            query = mn_session.query(
                FundIndicator.fund_id,
                FundIndicator.alpha,
                FundIndicator.beta,
                FundIndicator.track_err,
                FundIndicator.fee_rate,
            ).filter(FundIndicator.datetime==latest_time)
            df = pd.read_sql(query.statement, query.session.bind)
            df = df.rename(columns={'track_err': 'tag_track_err'})
            df = df.drop_duplicates(subset=['fund_id'], keep='last')
            return df

        except Exception as e:
            print('Failed get_fund_indicator_df <err_msg> {}'.format(e))

def append_data(table_name, data_append_directly_data_df):
    engine = create_engine(
            'mysql+pymysql://wangjun:Wangjun123456@fundinfo.cq1tbd5lkqzo.rds.cn-northwest-1.amazonaws.com.cn:3306/view')

    if not data_append_directly_data_df.empty:
        data_append_directly_data_df.to_sql(table_name, engine, index = False, if_exists = 'append')
        print('新数据已插入')
    else:
        print('没有需要插入的新数据')

def get_exchange_status(x):
    if x['redeem_status'] == ExchangeStatus.LIMITED:
        x['redeem_status'] = ExchangeStatus.OPEN
    if x['subscribe_status'] == ExchangeStatus.LIMITED:
        x['subscribe_status'] = ExchangeStatus.OPEN
    if x['redeem_status'] == ExchangeStatus.CLOSE and x['subscribe_status'] == ExchangeStatus.CLOSE:
        return '暂停交易'
    if x['redeem_status'] == ExchangeStatus.SUSPENDED:
        return '暂停赎回'
    if x['subscribe_status'] == ExchangeStatus.SUSPENDED:
        return '暂停申购'
    if x['redeem_status'] == ExchangeStatus.OPEN and x['subscribe_status'] == ExchangeStatus.OPEN:
        return '正常开放'
    return '暂无状态'

def get_found_to_now(x):
    if pd.isna(x):
        return None
    return round((pd.datetime.now().date() - x).days / 365, 2)

def modify_fund_manager(x):
    try:
        return x.split('\r\n')[-1].split('(')[0]
    except:
        return x

def compute_daily_collection():
    funds = get_fund_df()
    funds = funds.reset_index()
    funds = funds.drop_duplicates(subset=['fund_id'], keep='last')
    funds = funds.set_index('fund_id')
    print('info', funds)
    print('-' * 100)

    nav, latest_time = get_nav_df()
    print(latest_time)
    nav = nav.reset_index()
    nav = nav.drop_duplicates(subset=['fund_id'], keep='last')
    nav = nav.set_index('fund_id')
    print('nav', nav)
    print('-' * 100)

    alpha = get_alpha_df()
    alpha = alpha.set_index('fund_id')
    print(alpha)
    print('-' * 100)
    size = get_size_df()
    print(size)
    print('-' * 100)
    score = get_score_df().set_index('fund_id')
    print(score)
    print('-' * 100)
    tag_indicator = get_tag_fund_indicator_df().set_index('fund_id')
    print(tag_indicator)
    print('-' * 100)

    print('处理机构评级')
    rating = get_institution_rating_df()
    rating = rating.drop_duplicates(subset=['fund_id'], keep='last')
    rating = rating.set_index('fund_id')
    print(rating)
    print('-' * 100)

    print('处理净值')
    df = pd.concat([funds, nav, alpha, size, rating, score, tag_indicator], axis=1, sort=False)
    df.index.name = 'fund_id'
    print('_'*100)
    print(df)

    print('处理行情')
    indicator = get_indicator_df()
    indicator = indicator.dropna(subset=['order_book_id'])
    indicator['fund_id'] = indicator['order_book_id'] + '!0'
    indicator = indicator.drop_duplicates(subset=['order_book_id'], keep='last')
    indicator = indicator.drop(['order_book_id'], axis=1)
    indicator = indicator.set_index('fund_id')
    print(indicator)
    print('-' * 100)

    df = pd.concat([df, indicator], axis=1, sort=False, join_axes=[df.index])
    df.index.name = 'fund_id'
    df = df.reset_index()
    df = df.dropna(subset=['fund_id'])
    df['exchange_status'] = df.apply(get_exchange_status, axis=1)
    df['found_to_now'] = df['start_date'].apply(get_found_to_now)
    df['manager_id'] = df['manager_id'].apply(modify_fund_manager)
    df = df.rename(columns={
        'wind_class_1': 'wind_class_I',
        'start_date': 'found_date',
        'manager_id': 'fund_manager',
        'company_id': 'company_name',
        'desc_name': 'symbol',
    })
    df = df.drop(['redeem_status', 'subscribe_status'], axis=1)
    df = df.sort_values(['fund_id'])
    df = df.drop_duplicates(subset=['order_book_id'], keep='first')
    df = df.dropna(subset=['order_book_id'])

    # df.to_csv('./hhh.csv')
    append_data(FundDailyCollection.__tablename__, df)

    print(df)


if __name__ == '__main__':
    compute_daily_collection()


