# -*- coding: utf-8 -*-
import datetime as dt
import tushare as ts

import backtradercn.datas.utils as bdu
from backtradercn.settings import settings as conf
from backtradercn.libs.log import get_logger
from backtradercn.libs.models import get_or_create_library


logger = get_logger(__name__)


class TsHisData(object):
    """
    Mapping one collection in 'ts_his_lib' library, download and
    maintain history data from tushare, and provide other modules with the data.
    columns: open, high, close, low, volume
    Attributes:
        coll_name(string): stock id like '000651' for gree.

    """

    def __init__(self, coll_name):
        self._lib_name = conf.CN_STOCK_LIBNAME
        self._coll_name = coll_name
        self._library = get_or_create_library(self._lib_name)
        self._unused_cols = ['price_change', 'p_change', 'ma5', 'ma10', 'ma20',
                             'v_ma5', 'v_ma10', 'v_ma20', 'turnover']
        self._new_added_colls = []

    @classmethod
    def download_one_delta_data(cls, coll_name):
        """
        Download all the collections' delta data.
        :param coll_name: a stock code
        :return: None
        """
        ts_his_data = TsHisData(coll_name)
        ts_his_data.download_delta_data()

    @classmethod
    def download_all_delta_data(cls, *coll_names):
        """
        Download all the collections' delta data.
        :param coll_names: list of the collections.
        :return: None
        """
        for coll_name in coll_names:
            ts_his_data = TsHisData(coll_name)
            ts_his_data.download_delta_data()

    def download_delta_data(self):
        """
        Get yesterday's data and append it to collection,
        this method is planned to be executed at each day's 8:30am to update the data.
        1. Connect to arctic and get the library.
        2. Get today's history data from tushare and strip the unused columns.
        3. Store the data to arctic.
        :return: None
        """

        self._init_coll()

        if self._coll_name in self._new_added_colls:
            return

        # 15:00 PM can get today data
        # start = latest_date + 1 day
        latest_date = self.get_data().index[-1]
        start = latest_date + dt.timedelta(days=1)
        start = dt.datetime.strftime(start, '%Y-%m-%d')

        his_data = ts.get_hist_data(
            code=self._coll_name,
            start=start,
            retry_count=5
        )

        # delta data is empty
        if len(his_data) == 0:
            logger.info(
                f'delta data of stock {self._coll_name} is empty, after {start}')
            return

        his_data = bdu.Utils.strip_unused_cols(his_data, *self._unused_cols)

        logger.info(f'got delta data of stock: {self._coll_name}, after {start}')
        self._library.append(self._coll_name, his_data)

    def get_data(self):
        """
        Get all the data of one collection.
        :return: data(DataFrame)
        """

        data = self._library.read(self._coll_name).data
        # parse the date
        data.index = data.index.map(bdu.Utils.parse_date)

        return data

    def _init_coll(self):
        """
        Get all the history data when initiate the library.
        1. Connect to arctic and create the library.
        2. Get all the history data from tushare and strip the unused columns.
        3. Store the data to arctic.
        :return: None
        """

        # if collection is not initialized
        if self._coll_name not in self._library.list_symbols():
            self._new_added_colls.append(self._coll_name)
            his_data = ts.get_hist_data(code=self._coll_name, retry_count=5).sort_index()
            if len(his_data) == 0:
                logger.warning(
                    f'data of stock {self._coll_name} when initiation is empty'
                )
                return

            his_data = bdu.Utils.strip_unused_cols(his_data, *self._unused_cols)

            logger.debug(f'write history data for stock: {self._coll_name}.')
            self._library.write(self._coll_name, his_data)