import json
from datetime import datetime as dt
from typing import List
from urllib.parse import urlencode

import pandas as pd
import requests
from py_jftech import component, filter_weekend, next_workday, get_config, format_date

from api import RoboReportor
from reports.dao import robo_benckmark as rb

config = get_config(__name__)


@component(bean_name='benckmark-report')
class BenchmarkAlligamReportor(RoboReportor):

    @property
    def report_name(self) -> str:
        return 'BENCHMARK_ALLIGAM'

    @property
    def module_name(self) -> str:
        return 'divrobo'

    @property
    def risk(self):
        return 'alligam'

    @property
    def base_params(self):
        return {
            'subjectKeys': 879,
            'size': 200,
            'sourceType': 'BLOOMBERG'
        }

    def sync_benchmark(self, start_date=None):
        params = {
            **self.base_params,
            'page': 0
        }
        if start_date:
            params['startDate'] = format_date(start_date)
        while True:
            response = requests.get(f'http://jdcprod.thiztech.com/api/datas/asset-value?{urlencode(params)}').json()
            if not response['success']:
                raise Exception(f'''request jdc alligam failed: {response['status']}''')
            rb.batch_insert([{
                'date': dt.fromtimestamp(x['date'] / 1000),
                'module': self.module_name,
                'risk': self.risk,
                'nav': x['calibrateValue'],
                'remarks': json.dumps({
                    'av': x['originValue'],
                    'div': x['dividend'] if 'dividend' in x else 0
                }, ensure_ascii=False)
            } for x in response['body']['content']])
            if response['body']['last']:
                break
            else:
                params = {**params, 'page': params['page'] + 1}

    def load_report(self, max_date=dt.today(), min_date=None) -> List[dict]:
        max_date = filter_weekend(max_date)
        min_date = filter_weekend(min_date) if min_date else None
        last = rb.get_last_one(module=self.module_name, risk=self.risk, max_date=max_date)
        if not last or last['date'] < max_date:
            self.sync_benchmark(start_date=next_workday(last['date']) if last else None)
        result = pd.DataFrame(rb.get_list(max_date=max_date, min_date=min_date))
        result['av'] = result['remarks'].apply(lambda x: json.loads(x)['av'])
        result['div'] = result['remarks'].apply(lambda x: json.loads(x)['div'])
        result['acc'] = result.apply(lambda row: result[result['date'] <= row['date']]['div'].sum() + row['av'], axis=1)
        result = result[['date', 'av', 'div', 'acc', 'nav']]
        result.rename(columns={'nav': f'{self.risk}_nav', 'av': f'{self.risk}_av', 'div': f'{self.risk}_div', 'acc': f'{self.risk}_acc'}, inplace=True)
        return result.to_dict('records')