"""
This module holds code for the display board to send feedback to the OTA main board
"""

import asyncio
import json
import logging
import subprocess
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.error import HTTPError
from urllib.request import Request, urlopen

import aiohttp

from .utils import (
    OTA_ECP4_LOG,
    DeviceRole,
    buildIpAddressFromConfig,
    OTA_MAIN_BOARD_API_PORT,
    OTA_MAIN_BOARD_END_POINT,
    DISPLAY_API_PORT,
    fetchUrl,
    getDisplayService,
    MsiServices,
)

logger = logging.getLogger(OTA_ECP4_LOG)


def getMainBoardAddress(serial: int) -> str:
    """
    Returns the IP address of the main board as string

    :param serial: serial number
    """
    # simply use a controller role to reconstruct the main board address
    mainBoardIpAddress = buildIpAddressFromConfig(
        serial, role=DeviceRole.CONTROLLER_REMOTE_DISPLAY
    )
    return mainBoardIpAddress


async def sendOtaNotification(
    destinationIp: str,
    sourceIp: str,
    notification: str,
    retries: int = 10,
    sleep: int = 10,
) -> bool:
    """
    Notify the main board that the display board has successfully booted on ECP4.
    """
    url = f"http://{destinationIp}:{OTA_MAIN_BOARD_API_PORT}/{OTA_MAIN_BOARD_END_POINT}"
    payload = {"ip": sourceIp, "message": notification}

    async with aiohttp.ClientSession() as session:
        for _ in range(retries):
            response = await fetchUrl(session, url, data=payload, method="POST")
            if response:
                return True
            await asyncio.sleep(sleep)
    return False


def restartDisplayService(configuredServices: set[MsiServices]):
    """
    Restarts the display service from the given configured services.

    Args:
        configuredServices (set[MsiServices]): A set of configured services.

    """
    displayService = getDisplayService(configuredServices)
    logger.info(f"Restart {displayService} service.")
    subprocess.Popen(["systemctl", "restart", displayService])


def createDisplayBoardHttpServer(
    configuredServices: set[MsiServices], readyEvent: threading.Event
):
    """
    Starts a server for remote boards to send their status
    """

    class OtaDisplayHandler(BaseHTTPRequestHandler):
        def log_message(self, format, *args):
            pass  # Override to suppress logging

        def do_GET(self):
            if self.path == "/restartDisplayService":
                self.send_response(200)
                self.send_header("Access-Control-Allow-Origin", "*")
                self.send_header("Content-type", "application/json")
                self.end_headers()
                response_data = {"message": "OK"}
                self.wfile.write(json.dumps(response_data).encode())
                restartDisplayService(configuredServices)

            if self.path == "/update":
                self.send_response(200)
                self.send_header("Content-Type", "application/json")
                self.end_headers()
                response_data = {"message": "OK"}
                self.wfile.write(json.dumps(response_data).encode())

                logger.info("Start update")

            if self.path == "/ready":
                self.send_response(200)
                self.send_header("Content-Type", "application/json")
                self.end_headers()
                response_data = {"message": "OK"}
                self.wfile.write(json.dumps(response_data).encode())

                logger.info("Set ready event")

                readyEvent.set()

    httpServer = HTTPServer(("", DISPLAY_API_PORT), OtaDisplayHandler)
    screenThread = threading.Thread(target=httpServer.serve_forever)
    screenThread.daemon = True
    screenThread.start()
