import vh3
import typing
from saas.library.python.ferryman import Ferryman, FerrymanBatchWaiter
import yt.wrapper as yt
import json
from saas.tools.ferryman.nirvana.operations_logging import get_logger

debug_file = "debug.log"


@vh3.decorator.operation(owner='saas-robot', deterministic=False)
@vh3.decorator.nirvana_output_names("response")
@vh3.decorator.log(name=debug_file, level="debug", file_name_pattern=debug_file)
@vh3.decorator.autorelease_to_nirvana_on_trunk_commit(
    version="https://nirvana.yandex-team.ru/alias/operation/saas_ferryman_add_table/0.1.0",
    script_method="saas.tools.ferryman.nirvana.saas_ferryman_add_table",
    nirvana_quota="saas-ferryman",
)
def saas_ferryman_add_table(
    table: vh3.MRTable,
    namespace: vh3.String,
    fqdn: vh3.String,
    is_delta: vh3.Boolean = False,
    timestamp: vh3.Integer = None,
    format_: vh3.Enum[typing.Literal['json', 'message', 'simple', 'personal', 'geo_yt']] = None,
    process_id: vh3.String= vh3.expr.meta.workflow_uid
) -> vh3.JSON[typing.Any]:
    """
        Add table to saas ferryman

        Push received yt table to saas ferryman for selected service,
        the same with https://wiki.yandex-team.ru/jandekspoisk/saas/ferryman/#/add-table

        :param fqdn:
        :param table:
        :param namespace:
        :param is_delta:
        :param timestamp:
        :param format_:
        :param process_id:
    """
    logger = get_logger(debug_file)
    table = json.loads(table.read_text())
    fm = Ferryman(fqdn=fqdn)
    resp = fm.api.add_table(path=table['table'], cluster=table['cluster'], namespace=namespace, is_delta=is_delta, timestamp=timestamp, format_=format_, reqinfo=process_id)
    logger.info("Batch {} added to ferryman {}".format(resp['batch'], fqdn))
    return resp


@vh3.decorator.operation(owner='saas-robot', deterministic=False)
@vh3.decorator.nirvana_output_names("response")
@vh3.decorator.log(name=debug_file, level="debug", file_name_pattern=debug_file)
@vh3.decorator.autorelease_to_nirvana_on_trunk_commit(
    version="https://nirvana.yandex-team.ru/alias/operation/saas_ferryman_add_full_tables/0.1.0",
    script_method="saas.tools.ferryman.nirvana.saas_ferryman_add_full_tables",
    nirvana_quota="saas-ferryman",
)
def saas_ferryman_add_full_tables(
    tables: vh3.JSON[typing.Any],
    fqdn: vh3.String,
    format_: vh3.Enum[typing.Literal['json', 'message', 'simple', 'personal', 'geo_yt']] = None,
    process_id: vh3.String= vh3.expr.meta.workflow_uid
) -> vh3.JSON[typing.Any]:
    """
        Add a number of tables to saas ferryman

        Push a number of tables, represented in json format to saas ferryman, return json with id of batch to check status,
        the same with https://wiki.yandex-team.ru/jandekspoisk/saas/ferryman/#/add-full-tables

        :param fqdn:
        :param tables:
        :param format_:
        :param process_id:
    """
    logger = get_logger(debug_file)
    fm = Ferryman(fqdn=fqdn)
    resp = fm.api.add_full_tables(tables=tables, format_=format_, reqinfo=process_id)
    logger.info("Batch {} added to ferryman {}".format(resp['batch'], fqdn))
    return resp


@vh3.decorator.operation(owner='saas-robot', deterministic=False)
@vh3.decorator.nirvana_output_names("response")
@vh3.decorator.log(name=debug_file, level="debug", file_name_pattern=debug_file)
@vh3.decorator.autorelease_to_nirvana_on_trunk_commit(
    version="https://nirvana.yandex-team.ru/alias/operation/saas_ferryman_add_table_and_wait_searchable/0.1.0",
    script_method="saas.tools.ferryman.nirvana.saas_ferryman_add_table_and_wait_searchable",
    nirvana_quota="saas-ferryman",
)
def saas_ferryman_add_table_and_wait_searchable(
    table: vh3.MRTable[yt.ypath.TablePath],
    namespace: vh3.String,
    fqdn: vh3.String,
    is_delta: vh3.Boolean = False,
    timestamp: vh3.Integer = None,
    format_: vh3.Enum[typing.Literal['json', 'message', 'simple', 'personal', 'geo_yt']] = None,
    same_state_time_limit_minutes: vh3.Integer = 4*60,
    process_id: vh3.String= vh3.expr.meta.workflow_uid
) -> vh3.JSON[typing.Any]:
    """
        Combination of add table and wait table operations

        This operation adds table to saas ferryman and then wait when this table gets searchable status,
        if searchable status will not be reached in selected period of time, operation will be interrupted

        :param fqdn:
        :param table:
        :param namespace:
        :param is_delta:
        :param timestamp:
        :param format_:
        :param same_state_time_limit_minutes:
        :param process_id:
    """
    logger = get_logger(debug_file)
    table = json.loads(table.read_text())
    fm = Ferryman(fqdn=fqdn)
    batch_id = fm.api.add_table(path=table['table'], cluster=table['cluster'], namespace=namespace, is_delta=is_delta, timestamp=timestamp, format_=format_, reqinfo=process_id)['batch']
    logger.info("Batch {} added to ferryman {}".format(batch_id, fqdn))
    logger.info("Waiting for batch {} in status searchable".format(batch_id))
    batch_waiter = FerrymanBatchWaiter(batch_id, fm, max_minutes_in_same_state=same_state_time_limit_minutes)
    resp = batch_waiter.wait_batch_status(["searchable"])
    logger.info("Batch {} now has reached status {}".format(batch_id, resp[-1]['status']))
    return resp


@vh3.decorator.operation(owner='saas-robot', deterministic=False)
@vh3.decorator.nirvana_output_names("response")
@vh3.decorator.log(name=debug_file, level="debug", file_name_pattern=debug_file)
@vh3.decorator.autorelease_to_nirvana_on_trunk_commit(
    version="https://nirvana.yandex-team.ru/alias/operation/saas_ferryman_wait_batch/0.1.0",
    script_method="saas.tools.ferryman.nirvana.saas_ferryman_wait_batch",
    nirvana_quota="saas-ferryman",
)
def saas_ferryman_wait_batch(
    statuses: vh3.MultipleEnums[typing.Literal['searchable', 'final', 'error', 'unknown', 'processing']],
    fqdn: vh3.String,
    batch: vh3.JSON[typing.Any],
    same_state_time_limit_minutes: vh3.Integer = 4*60,
    process_id: vh3.String= vh3.expr.meta.workflow_uid
) -> vh3.JSON[typing.Any]:
    """
        Wait selected status for ferryman batch

        Wait when ferryman batch reaches selected status, if status will not be reached in selected period of time,
        operation will be interrupted

        :param fqdn:
        :param batch:
        :param statuses:
        :param same_state_time_limit_minutes:
        :param process_id:
    """
    logger = get_logger(debug_file)
    fm = Ferryman(fqdn=fqdn)
    batch_waiter = FerrymanBatchWaiter(batch['batch'], fm, max_minutes_in_same_state=same_state_time_limit_minutes, reqinfo=process_id)
    resp = batch_waiter.wait_batch_status(statuses)
    logger.info("Batch {} now in reached status {}".format(batch['batch'], resp[-1]['status']))
    return resp
