import os
import re
import time
from six import string_types
import yt.wrapper as yt_wrapper
from datacloud.config.yt import YT_PROXY
from datacloud.dev_utils.configs import patterns
from datacloud.dev_utils.logging.logger import get_basic_logger

logger = get_basic_logger(__name__)

ypath_join = yt_wrapper.ypath_join
TablePath = yt_wrapper.TablePath


def create_folders(folders, yt_client):
    if isinstance(folders, string_types):
        folders = [folders]

    for folder in folders:
        if not yt_client.exists(folder):
            logger.info('mkdir {}'.format(folder))
            yt_client.mkdir(folder, recursive=True)


def check_table_exists(table_path, yt_client=None):
    yt_client = yt_client or get_yt_client(YT_PROXY)
    return yt_client.exists(table_path) and yt_client.row_count(table_path) > 0


def get_last_table(folder, yt_client=None):
    yt_client = yt_client or get_yt_client(YT_PROXY)
    max_table = ''
    for table in yt_client.list(folder, absolute=True):
        date_str = table.split('/')[-1]
        if re.match(patterns.YEAR_MONTH_DAY_PATTERN, date_str) and table > max_table:
            max_table = table
    return max_table


def get_k_last_tables(folder, k, yt_client=None):
    def table_filter(table_path):
        date_str = table_path.split('/')[-1]
        return re.match(patterns.YEAR_MONTH_DAY_PATTERN, date_str)

    yt_client = yt_client or get_yt_client(YT_PROXY)

    tables = yt_client.list(folder, absolute=True)
    tables = filter(table_filter, tables)
    tables = sorted(
        tables,
        key=lambda table_path: table_path.split('/')[-1]
    )

    return tables[-k:]


def get_yt_client(proxy=YT_PROXY, token=None, config=None):
    yt_wrapper.config.set_proxy(proxy)
    yt_client = yt_wrapper.YtClient(proxy=proxy, config=config)
    yt_client.config['token'] = token or yt_wrapper.config['token'] or os.environ.get('YT_TOKEN')
    return yt_client


def is_sorted_by(yt_client, table, columns):
    n_columns = len(columns)
    return (yt_client.is_sorted(table) and
            yt_client.get_attribute(table, 'sorted_by', [])[:n_columns] == columns)


def remove_table(table_path, yt_client):
    yt_client.remove(table_path)
    while yt_client.exists(table_path):
        time.sleep(0.1)


class DynTable(object):
    @staticmethod
    def mount(table_path, yt_client):
        yt_client.mount_table(table_path)
        while yt_client.get("{0}/@tablets/0/state".format(table_path)) != 'mounted':
            time.sleep(1)

    @staticmethod
    def remove_table(table_path, yt_client):
        remove_table(table_path, yt_client)

    @staticmethod
    def create_table(table_path, schema, yt_client, force=False):
        if yt_client.exists(table_path):
            if force:
                logger.info('Overwrite table {}'.format(table_path))
                DynTable.remove_table(table_path, yt_client)
            else:
                logger.info('Table {} exists, skip. Use force=True to overwrite'.format(table_path))
        yt_client.create(
            'table',
            table_path,
            attributes={
                'schema': schema,
                'dynamic': True,
            }
        )
        DynTable.mount(table_path, yt_client)

    @staticmethod
    def insert_row(table_path, yt_client, records):
        yt_client.insert_rows(
            table_path,
            records
        )

    @staticmethod
    def remove_row(table_path, yt_client, records):
        yt_client.delete_rows(
            table_path,
            records
        )

    @staticmethod
    def list_rows(yt_client, request):
        """
        params:
            request(str) : '* FROM [//yt/table_path] WHERE param1 == "value1" AND param2 == "value"'
        """
        return yt_client.select_rows(request)

    @staticmethod
    def get_rows_from_table(table, param_dict, yt_client):
        request = '* FROM [{}] WHERE '.format(table)
        counter = 0
        for key, val in param_dict.iteritems():
            if counter != 0:
                request += 'AND '
            if isinstance(val, string_types):
                request += '{} = "{}" '.format(key, val)
            else:
                request += '{} = {} '.format(key, val)
            counter += 1

        return yt_client.select_rows(request)
