# -*- coding: utf-8 -*-
from textwrap import dedent
from datacloud.dev_utils.transfer.yt_to_ydb import table_description
from datacloud.dev_utils.yql import yql_helpers


class ScorePathTableDescription(table_description.YdbTableDescription):
    def __init__(self, table_path, ydb_connection_params):
        super(ScorePathTableDescription, self).__init__(table_path, ydb_connection_params)
        self.schema = dedent("""\
        (
            internal_score_name String,
            score_path String
            primary key (internal_score_name)
        )
        """)

        self.fields = """
            internal_score_name,
            score_path
        """

    class Record(object):
        __slots__ = ('internal_score_name', 'score_path')

        def __init__(self, internal_score_name, score_path=''):
            self.internal_score_name = internal_score_name
            self.score_path = score_path

        def __str__(self):
            return '({}: {})'.format(self.internal_score_name, self.score_path)

        def __repr__(self):
            return self.__str__()

        def __eq__(self, other):
            return self.internal_score_name == other.internal_score_name and self.score_path == other.score_path

    def select(self, yql_client, internal_score_name):
        query = self._select_request.format(ydb_table=self, internal_score_name=internal_score_name)
        resp = yql_client.query(query, syntax_version=1).run().get_results()
        table = list(resp)[0]

        return [self.Record(*row) for row in table.rows]

    def _run_records_request(self, yql_client, records, query):
        values = ',\n'.join(self._record_value.format(record=record) for record in records)
        query = query.format(ydb_table=self, values=values)
        request = yql_client.query(query, syntax_version=1).run()

        if not request.is_success:
            raise yql_helpers.YqlExecutionException((request.status, list(map(str, request.errors))))

    def replace(self, yql_client, records):
        self._run_records_request(yql_client=yql_client, records=records, query=self._replace_request)

    def insert(self, yql_client, records):
        self._run_records_request(yql_client=yql_client, records=records, query=self._insert_request)

    def replace_path(self, yql_client, internal_score_name, new_score_path):
        records = self.select(yql_client, internal_score_name)
        assert len(records) > 0, 'internal_score_name {} not found'.format(internal_score_name)

        # TODO Add assertion that full path really exists and non empty
        old_score_path = records[0].score_path

        new_rec = records[0]
        new_rec.score_path = new_score_path

        self.replace(yql_client, [new_rec])
        return old_score_path

    _select_request = dedent("""\
        USE `{ydb_table.connection_params.database}`;
        SELECT
            {ydb_table.fields}
        FROM `{ydb_table.path}`
        WHERE internal_score_name == "{internal_score_name}"
    """)

    _record_value = dedent("""\
        (
            "{record.internal_score_name}",
            "{record.score_path}"
        )
    """)

    _replace_request = dedent("""\
        USE `{ydb_table.connection_params.database}`;
        UPSERT INTO `{ydb_table.path}` (
            {ydb_table.fields}
        )
        VALUES {values}
    """)

    _insert_request = dedent("""\
        USE `{ydb_table.connection_params.database}`;
        INSERT INTO `{ydb_table.path}` (
            {ydb_table.fields}
        )
        VALUES {values}
    """)
