import asyncio
import ipaddress
import logging
import os
from pathlib import Path

from aiohttp import web

from notedrive.magnet import settings
from notedrive.magnet.core import Magnet2Torrent
from notedrive.magnet.dht.network import Server as DHTServer
from notedrive.magnet.server import routes
from notedrive.magnet.utils import FailedToFetchException


def start_serve(dht_server, torrent_cache_folder=None, debug=False, apikey=None, ip=ipaddress.IPv4Address("0.0.0.0"),
                port=18667, ):
    if not debug:
        stdio_handler = logging.StreamHandler()
        stdio_handler.setLevel(logging.INFO)
        logger = logging.getLogger("aiohttp.access")
        logger.setLevel(logging.INFO)
        logger.addHandler(stdio_handler)

    settings.SERVE_APIKEY = apikey
    settings.DHT_SERVER = dht_server
    settings.TORRENT_CACHE_FOLDER = torrent_cache_folder
    app = web.Application()
    app.add_routes(routes)
    web.run_app(app, host=str(ip), port=port)


def start_fetch(dht_server, torrent_cache_folder=None, dht_state_file=None, magnet=None, ):
    loop = asyncio.get_event_loop()
    m2t = Magnet2Torrent(dht_server=dht_server, torrent_cache_folder=torrent_cache_folder, use_additional_trackers=True)
    try:
        torrent = loop.run_until_complete(m2t.retrieve_torrent(magnet_link=magnet))
    except FailedToFetchException:
        print("Unable to fetch magnet link")
        quit(1)
    else:
        with open(torrent.name, "wb") as f:
            f.write(torrent.data_encode())

        print("Downloaded magnet link into file: {}".format(torrent.name))

    if dht_server and dht_state_file:
        dht_server.save_state(dht_state_file)


def start(torrent_cache_folder=None, debug=False, use_dht=False, dht_state_file=None, dht_port=settings.DHT_PORT,
          dht_ip=ipaddress.IPv4Address("0.0.0.0"), command='serve', apikey=None, ip=ipaddress.IPv4Address("0.0.0.0"),
          port=18667, magnet=None, ):
    if torrent_cache_folder:
        torrent_cache_folder = Path(torrent_cache_folder)

        if not torrent_cache_folder.exists():
            os.makedirs(torrent_cache_folder)

        if not torrent_cache_folder.is_dir():
            print("Path {} exists but is not a folder".format(torrent_cache_folder))
            quit(1)

    if debug:
        logging.basicConfig(level=logging.DEBUG, format="%(asctime)-15s:%(levelname)s:%(name)s:%(lineno)d:%(message)s")

    if use_dht:
        print("Bootstrapping DHT server")
        loop = asyncio.get_event_loop()
        dht_server = DHTServer()

        if dht_state_file and os.path.isfile(dht_state_file):
            dht_server = DHTServer.load_state(dht_state_file)
            loop.run_until_complete(dht_server.listen(dht_port, str(dht_ip)))
        else:
            dht_server = DHTServer()
            loop.run_until_complete(dht_server.listen(dht_port, str(dht_ip)))
            loop.run_until_complete(dht_server.bootstrap(settings.DHT_BOOTSTRAP_NODES))

        if dht_state_file:
            dht_server.save_state_regularly(dht_state_file)
        print("Done bootstrapping DHT server")
    else:
        dht_server = None

    if command == "serve":
        start_serve(dht_server, torrent_cache_folder=torrent_cache_folder, debug=debug, apikey=apikey, ip=ip, port=port)
    elif command == "fetch":
        start_fetch(dht_server, torrent_cache_folder=torrent_cache_folder, dht_state_file=dht_state_file, magnet=magnet)
