# -*- coding: utf-8 -*-
from datacloud.dev_utils.yt import yt_utils
from datacloud.dev_utils.time import utils as time_utils
from datacloud.dev_utils.time import patterns
from datacloud.dev_utils.logging.logger import get_basic_logger

logger = get_basic_logger(__name__)

__all__ = [
    'TableConverter',
    'PipelineConverter',
    'COperation'
]


class ConverterException(Exception):
    pass


# TODO: Add chain
class TableConverter(object):
    def __init__(self, yt_client):
        self._yt_client = yt_client
        self._prev = None
        self._yt_tmp_folder = '//tmp/x-prod-converter'
        self._was_used = False

    def convert(self, input_table, output_table):
        logger.info(' start : {}'.format(self))
        if self._was_used is True:
            raise ConverterException('TableConverter `{}` was already used. Check your operations.'.format(self))
        if self._prev:
            if not self._yt_client.exists(self._yt_tmp_folder):
                yt_utils.create_folders([self._yt_tmp_folder], self._yt_client)
            tmp_table = yt_utils.ypath_join(self._yt_tmp_folder, '{}-{}'.format(str(self._prev), time_utils.now_str(patterns.FMT_DATE_HM)))
            self._prev.convert(input_table, tmp_table)
            input_table = tmp_table
            logger.info(' back to : {}'.format(self))
        self._convert(input_table, output_table)
        logger.info(' save results to: {}'.format(output_table))
        self._was_used = True
        logger.info(' done : {}'.format(self))

    def describe(self):
        if self._prev is not None:
            self._prev.describe()
        print('{} =>'.format(self))

    def _convert(self, input_table, output_table):
        raise NotImplementedError('Implement `convert` in child class')

    def __lshift__(self, other):
        assert isinstance(other, TableConverter), '`other` operation must be TableConveter'
        self._prev = other
        # Because << is left associative.  a << b << c will work correctly a._prev = b; b._prev = c
        return self._prev

    def __ror__(self, other):
        assert isinstance(other, TableConverter), '`other` operation must be TableConveter'
        self._prev = other
        return self

    def __call__(self, input_table, output_table):
        return self.convert(input_table, output_table)

    def __str__(self):
        return self.__class__.__name__


class PipelineConverter(TableConverter):
    def __init__(self, yt_client):
        super(PipelineConverter, self).__init__(yt_client)

    def _convert(self, input_table, output_table):
        logger.info('Copy {} to {}'.format(input_table, output_table))
        self._yt_client.copy(input_table, output_table)


class COperation(TableConverter):
    def __init__(self, yt_client):
        super(TableConverter, self).__init__(yt_client)

    def _convert(self, input_table):
        raise NotImplementedError('Implement `convert` in child class')

    # TODO: Overload __lshift__, __ror__ and check that only Opeartion (not TableConverter) can be shifted,
    # becouse operation doesn't have output table
