from typing import Optional
from typing import Iterable
import logging
import time


def consume_publish_run(
        consumer,
        db_wrapper,
        sleep_time: int,
        topics: Optional[Iterable[str]] = None,
        cycles: Optional[int] = None,
        db_schema: Optional[str] = None,
        db_table: Optional[str] = None
):
    """Service runner for fetching data from Kafka broker and posting to DB

    Args:
        consumer: Kafka consumer
        db_wrapper: helper lib to work with DB
        sleep_time: number of seconds to wait between metric collection
        topics: to change to. When provided, previous topics are wiped out
        cycles: number of iterations to run the service. Runs infinitely if None
        db_schema: database schema (in postgres understanding) to store data
        db_table: database table to store data

    Returns:
        None, runs until interrupted by user or iterated "iterations" times

    """

    if topics:
        consumer.change_topics(topics)
    log = logging.getLogger(f'{__file__}:ConsumerAndPublishingService')
    log.addHandler(logging.NullHandler())

    with consumer:
        counter = 0
        def proceed(): return counter < cycles if cycles else True
        while True:
            try:
                data = consumer.fetch_latest()
                if not data:
                    log.warning('No data to push to DB. Is web metric service running?')
                else:
                    log.info(f'Successfully fetched {len(data)} pieces of data')
                    db_wrapper.insert(data, schema=db_schema, table=db_table)
                counter += 1
                if not proceed():
                    log.info(f'Exiting service because it worked {counter} out of {cycles} cycles')
                    break
                time.sleep(sleep_time)
            except KeyboardInterrupt:
                break