#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# External Dependencies
import kivy

kivy.require("2.3.1")
# Standard Library
import asyncio
import concurrent.futures
import logging
import traceback

from .display import IronCastApp
from .hdmi import CECController
from .server import create_web_server
from .ssdp import create_ssdp_server

logger = logging.getLogger("__name__")


class WorkerThread:
    def __init__(self):
        self._loop_future = concurrent.futures.Future()
        self._taskgroup_future = concurrent.futures.Future()
        self._shutdown_event = asyncio.Event()

        self._executor = concurrent.futures.ThreadPoolExecutor(1)
        self._overall_future = self._executor.submit(asyncio.run, self.main_runner())

        self._loop = self._loop_future.result()
        self._taskgroup = self._taskgroup_future.result()

    class ShutdownException(Exception):
        pass

    async def main_runner(self):
        try:
            async with asyncio.TaskGroup() as tg:
                self._loop_future.set_result(asyncio.get_running_loop())
                self._taskgroup_future.set_result(tg)
                await self._shutdown_event.wait()
                raise self.ShutdownException
        except* self.ShutdownException:
            pass

    def __enter__(self):
        return self

    def __exit__(self, *args, **kwargs):
        try:
            self._loop.call_soon_threadsafe(self._shutdown_event.set)
            self._overall_future.result()
        finally:
            self._executor.shutdown()

    def __call__(self):
        self._loop.call_soon_threadsafe(self._taskgroup.create_task, self._run())

    async def _run(self):
        try:
            async with asyncio.TaskGroup() as tg:
                tg.create_task(create_ssdp_server())
                tg.create_task(create_web_server())
        except* Exception as e:  # pylint: disable=broad-exception-caught
            for exception in e.exceptions:
                logger.error("".join(traceback.format_exception(exception)))


def cli():
    gui = IronCastApp()
    t = CECController()
    t.start()

    with WorkerThread() as worker:
        worker()
        try:
            gui.run()
        except KeyboardInterrupt:
            pass


if __name__ == "__main__":
    cli()
