import time
from concurrent.futures import Future
from functools import partial

from .. import Keys
from ..Activity import Activity
from ..CentralDispatch import CentralDispatch
from ..ContextUtils import scroll_up, scroll_down, scroll_to_bottom, get_items_len
from ..EventTypes import KeyStroke, ScrollChange, TextBoxSubmit
from ..input_handlers import handle_text_box_input, handle_scroll_list_input
from ..printers.printers import WrappedScrollList
from ..printers.TopBar import TopBar
from ..printers.TextInput import TextInput
from ..printers.BottomBar import BottomBar as PBottomBar
from loguru import logger


class LogViewerActivity(Activity):

    def __init__(self):
        super().__init__()
        self.tab_order = ["log_output", "search_bar"]

        self.focus = "log_output"
        self.stop_signal = False
        self.log_watcher: Future = None

    def on_start(self):
        self.application.subscribe(KeyStroke, self, self.on_key_stroke)
        self.application.subscribe(TextBoxSubmit, self, self.on_enter_pressed)
        self.application.subscribe(ScrollChange, self, self.on_scroll_change)

        wrapped_scroll_list = WrappedScrollList(self.screen)
        self.display_state = {
            "top_bar": TopBar.display_state(
                items={"title": "Application Log", "help": "Press ESC to go back"}
            ),
            "log_output": {
                "items": [],
                "focused": False,
                "selected_index": 0,
                "layout": {"flex": 1, "min_height": 5},
                "line_generator": wrapped_scroll_list,
                "input_handler": handle_scroll_list_input,
            },
            "search_bar": TextInput.display_state(
                label="Search",
                text="",
                focused=False,
                input_handler=handle_text_box_input,
            ),
            "bottom_bar": PBottomBar.display_state(items={}),
        }

        self.display_state[self.focus]["focused"] = True
        self.log_watcher = CentralDispatch.future(self._run_log_watcher, self.application.log_filename)

    def on_stop(self):
        self.stop_signal = True
        self.log_watcher.result()

    def update_scroll_percent(self):
        log_context = self.display_state["log_output"]
        bottom_context = self.display_state["bottom_bar"]
        index = log_context.get("selected_index", 0)
        num_items = get_items_len(log_context)

        if num_items is not None:
            percent = int((index/num_items)*100)
        else:
            percent = 0

        bottom_context["items"]["scroll_percent"] = f"Scroll: {percent}% | Selected Index: {index}"
        self.refresh_screen()

    def on_new_log_line(self, line):
        log_context = self.display_state["log_output"]
        log_items = log_context["items"]
        is_at_bottom = log_context.get("selected_index", 0) == len(log_items) - 1
        log_items.append(line)

        if is_at_bottom:
            scroll_to_bottom(log_context)
        self.display_state["bottom_bar"]["items"]["num_lines"] = f"Lines: {len(log_items)}"
        self.refresh_screen()

    def on_new_log_lines(self, lines):
        log_items = self.display_state["log_output"]["items"]
        for line in lines:
            log_items.append(line)

        scroll_to_bottom(self.display_state["log_output"])
        self.display_state["bottom_bar"]["items"]["num_lines"] = f"Lines: {len(log_items)}"
        self.refresh_screen()

    def on_enter_pressed(self, event: TextBoxSubmit):
        text = self.display_state["search_bar"]["text"]
        logger.info(f"You just pressed enter: {text}")

    def on_key_stroke(self, event: KeyStroke):
        self.delegate_to_focused(event)

        if event.key == Keys.BACKSPACE:
            logger.info("You pressed backspace!")

        if event.key == Keys.ESC:
            self.application.pop_activity()

        if event.key == Keys.TAB:
            logger.info("You pressed tab!")
            self.cycle_focus()

        self.refresh_screen()

    def on_scroll_change(self, event: ScrollChange):
        self.update_scroll_percent()

    def _run_log_watcher(self, log_filename):
        """This is my favorite function"""
        with open(log_filename, 'r') as log_file:
            starting_lines = []
            where = log_file.tell()
            line = log_file.readline()

            while line:
                starting_lines.append(line.strip())
                where = log_file.tell()
                line = log_file.readline()
            log_file.seek(where)

            self.main_thread.submit_async(self.on_new_log_lines, starting_lines)

            while not (self.stop_signal or self.application.shutdown_signal.done()):
                lines = []
                where = log_file.tell()
                line = log_file.readline()

                while line:
                    lines.append(line.strip())
                    where = log_file.tell()
                    line = log_file.readline()
                log_file.seek(where)
                if len(lines) > 0:
                    self.main_thread.submit_async(self.on_new_log_lines, lines)
                time.sleep(.1)
