import asyncio
from aiohttp import web, hdrs

from web_interface.auth import check_auth
from web_interface.detected_printers_html import printer_form_html

def get_network_detector(request):
    app = request.app['3dp_app']
    network_detector = app.detectors.get('NetworkDetector')
    if not network_detector:
        raise web.HTTPInternalServerError(text='NetworkDetector disabled')
    return network_detector

async def network_printers(request):
    check_auth(request)
    network_detector = get_network_detector(request)
    return web.json_response(network_detector.get_printers_list())

async def remember_network_printer(request):
    check_auth(request)
    if request.content_type == 'application/json':
        post_data = await request.json()
    else:
        post_data = await request.post()
    printer_ip = post_data.get('printer_ip')
    printer_port = post_data.get('printer_port')
    printer_type = post_data.get('printer_type')
    conn_id = post_data.get('connection_id')
    run_detector = post_data.get('run_detector', False)
    password = post_data.get('password')
    if password == '':
        password = None
    ssh_password = post_data.get('ssh_password')
    if ssh_password == '':
        ssh_password = None
    vid = post_data.get('vid')
    pid = post_data.get('vid')
    serial_number = post_data.get('serial_number', post_data.get('forced_snr', post_data.get('forced_SNR', '')))
    run_detector = bool(not serial_number and run_detector == 'on')
    try:
        printer_port = int(printer_port)
    except (TypeError, ValueError):
        printer_port = None
    network_detector = get_network_detector(request)
    if not printer_type:
        raise web.HTTPBadRequest(text="Error: empty printer type")
    if not printer_ip:
        raise web.HTTPBadRequest(text="Error: empty printer ip")
    network_detector.remember_printer(printer_type, printer_ip, printer_port, vid, pid, serial_number, password, ssh_password, run_detector, conn_id)
    return web.HTTPOk()

async def forget_network_printer(request):
    check_auth(request)
    if request.content_type == 'application/json':
        post_data = await request.json()
        printer_id = post_data.get('printer_id')
    elif request.method == hdrs.METH_POST:
        post_data = await request.post()
        printer_id = post_data.get('printer_id')
    else:
        printer_id = request.query.get('printer_id')
    if not printer_id:
        printer_id = request.match_info.get('printer_id')
    if not printer_id:
        return web.HTTPBadRequest(text='No printer id. Could be string or json_dict or form dict')
    network_detector = get_network_detector(request)
    if isinstance(printer_id, str):
        try: 
            vid, pid, snr = printer_id.split('_', 2)
        except ValueError:
            raise web.HTTPBadRequest(text='Invalid printer id: ' + printer_id)
        printer_id = {'VID': vid, 'PID': pid, 'SNR': snr}
    if network_detector.forget_printer(printer_id):
        return web.HTTPOk()
    return web.HTTPNotFound(text=f'No printer with id {printer_id} to forget')

async def detect_printers(request):
    check_auth(request)
    net_detector = get_network_detector(request)
    detection_future = asyncio.get_event_loop().run_in_executor(request.app['threads_pool'], net_detector.detect)
    await asyncio.wait_for(detection_future, 60)
    return web.json_response(data=net_detector.get_just_detected_printers(clear=True))

async def scanners_table(request):
    net_detector = get_network_detector(request)
    return web.json_response(data=net_detector.get_scanners_table())

async def get_printer_types_by_scanner(request):
    net_detector = get_network_detector(request)
    scanners_table = net_detector.get_scanners_table()
    post_data = await request.json()
    scanner_name = post_data.get('SCNR')
    vid = post_data.get('VID')
    pid = post_data.get('PID')
    conn_id = post_data.get('PID')
    possible_types = []
    if not scanner_name in scanners_table:
        raise web.HTTPBadRequest(text='Unknown scanner name ' + str(scanner_name))
    for vids_pids, profile, this_conn_id in scanners_table[scanner_name]:
        if not vid and not pid or {'VID': pid, 'PID': pid} in vids_pids:
            if not conn_id or conn_id == this_conn_id:
                possible_types = profile['name']
    return web.json_response(data=possible_types)

async def detected_printers_html_list(request):
    net_detector = get_network_detector(request)
    scanners_table = net_detector.get_scanners_table()
    # profiles = net_detector.get_all_network_profiles()
    detection_future = asyncio.get_event_loop().run_in_executor(request.app['threads_pool'], net_detector.detect)
    await asyncio.wait_for(detection_future, 60)
    forms_htmls = []
    for printer in net_detector.get_just_detected_printers():
        ip = printer.get('IP', "")
        port = printer.get('PORT', "")
        vid = printer.get('VID', "")
        pid = printer.get('PID', "")
        snr = printer.get('SNR', "")
        password = printer.get('PASS', "")
        ssh_password = printer.get('SSHP', "")
        if vid and pid:
            this_vid_pid = {'VID': vid, 'PID': pid}
        else:
            this_vid_pid = None
        possible_types = []
        for vids_pids, profile, conn_id in scanners_table.get(printer['SCNR']):
            if not vid or not vid or this_vid_pid in vids_pids:
                possible_types.append((profile, conn_id))
        forms_htmls.append(printer_form_html(ip, port, vid, pid, snr, password, ssh_password, None, None, possible_types))
    return forms_htmls

async def detected_printers_list_html(request):
    check_auth(request)
    return web.Response(text="\n".join(await detected_printers_html_list(request)), content_type="text/html")
