import itertools
import curses
import curses.panel
import logging

from lib.ui import *

from lib.console import ConsoleInput
from lib.event import VTEvent
from lib.types import Controller

import asyncio
from aiorun import run

logging.basicConfig(filename='vtrack420.log', encoding='ascii', level=logging.DEBUG)

logger = logging.getLogger('vtrack420')

def _newwin(*args, **kwargs):
    win = curses.newwin(*args, **kwargs)
    win.leaveok(True)
    win.nodelay(True)
    win.keypad(True)

    return win

class VTrack420(Controller):
    def __init__(self, stdscr):
        curses.curs_set(False)

        self.running = True
        
        self.stdscr = stdscr
        self.lines, self.cols = stdscr.getmaxyx()

        self.main_window = _newwin(self.lines - 3, self.cols, 3, 0)
        self.main_window.border(0, 0, ' ', 0, curses.ACS_VLINE, curses.ACS_VLINE)
        self.main_window.noutrefresh()

        self.components = []
        self.tabs = []

        # Global events

        self.ev_tab_switch = VTEvent()

    async def start(self):
        self.loop = asyncio.get_running_loop()

        await self.start_components()

        # Time screen refreshes
        while self.running:
            await asyncio.sleep(1/60)
            curses.doupdate()
        
        self.loop.stop()

    async def handle_input(self, chars):
        for c in chars:
            # Handle global input
            logger.debug(f"Got input: {c!r}")
            match c:
                case "q":
                    self.running = False
                case "\t":
                    await self.next_tab()
                case _:
                    await self.active_tab.handle_input(c)

    def get_inner_window(self):
        begin_y, begin_x = self.main_window.getbegyx()
        end_y, end_x   = self.main_window.getmaxyx()

        inner_lines = end_y - begin_y - 2
        inner_cols  = end_x - begin_x - 6

        return _newwin(inner_lines, inner_cols, begin_y + 1, begin_x + 3)

    async def start_components(self):
        await self.add_tab(TrackTab)
        await self.add_tab(ManageTab)
        
        await self.set_tab(self.tabs[0])

        self.components.append(ConsoleInput(
            controller=self,
            window=self.main_window))

        self.components.append(StatusBar(
            controller=self,
            window=_newwin(1, self.cols, 0, 0)))

        self.components.append(TabBar(
            controller=self,
            window=_newwin(2, self.cols, 1, 0), 
            tabs=self.tabs))

        for component in self.components:
            self.loop.create_task(component.start())
            if isinstance(component, SubWindow):
                component.draw()

    async def add_tab(self, tab_cls):
        tab = tab_cls(self, self.get_inner_window())
        self.loop.create_task(tab.start())
        self.tabs.append(tab)


    async def next_tab(self):
        # clear main window
        self.main_window.touchwin()
        self.main_window.noutrefresh()

        old_tab = self.active_tab

        tab_iter = itertools.cycle(iter(self.tabs))
        while (tab := next(tab_iter)):
            if tab == self.active_tab:
                await tab.switch_out()
                break

        new_tab = next(tab_iter)

        await self.set_tab(new_tab, old_tab=old_tab)
    
    async def set_tab(self, new_tab, old_tab=None):
        self.active_tab = new_tab
        await new_tab.switch_in()

        async with self.ev_tab_switch:
            self.ev_tab_switch.notify_all(old_tab, new_tab)


def main(stdscr):
    vtrack420 = VTrack420(stdscr)
    try:
        asyncio.run(vtrack420.start(), debug=True)
    except KeyboardInterrupt:
        pass

curses.wrapper(main)
