import json
import subprocess
from http.server import HTTPServer, BaseHTTPRequestHandler
import os.path as path
import threading
import socket
import errno
import logging

from .settings import SCREEN_PORT, SCREEN_TEMPLATE, OTA_RESCUE_LOGGER_NAME

otalogger = logging.getLogger(OTA_RESCUE_LOGGER_NAME)


def provideFirmwareUpdateScreen(workdir: str, ipAddress: str):

    setGPIO("/sys/class/gpio/gpio161/value", "1")
    setGPIO("/sys/class/gpio/gpio159/value", "1")
    setGPIO("/sys/class/gpio/gpio158/value", "1")

    def startServer():
        httpServer = HTTPServer(
            ("", SCREEN_PORT), createRequestHandler(workdir, ipAddress)
        )
        httpServer.serve_forever()

    screenThread = threading.Thread(target=startServer)
    screenThread.daemon = True
    screenThread.start()


def setGPIO(path: str, value: str):
    try:
        with open(path, "w") as gpio:
            gpio.write(value)
    except (OSError, IOError) as e:
        otalogger.info(f"Error setting GPIO: {e}")


def createRequestHandler(workdir: str, ipAddress: str) -> BaseHTTPRequestHandler:
    class RequestHandler(BaseHTTPRequestHandler):
        html = None

        def load_html(self):
            """Load the HTML file and replace placeholders."""

            sourcePath = path.join(path.dirname(__file__), "resources", SCREEN_TEMPLATE)
            if path.exists(sourcePath):
                with open(sourcePath, "r") as file:
                    self.html = file.read().replace(
                        "var URL = ''",
                        f"var URL = 'http://{ipAddress}:{SCREEN_PORT}/status'",
                    )

        def do_GET(self):
            if self.path in ["", "/", "/index.html", "/index.htm"]:
                if not self.html:
                    self.load_html()

                self.send_response(200)
                self.send_header("Access-Control-Allow-Origin", "*")
                self.send_header("Content-type", "text/html")
                self.end_headers()
                try:
                    self.wfile.write(self.html.encode("utf-8"))
                except BrokenPipeError as err:
                    otalogger.info(f"Broken pipe {err}")

            elif self.path == "/status":
                filePath = path.join(workdir, "status.json")
                if path.isfile(filePath):
                    try:
                        self.send_response(200)
                        self.send_header("Access-Control-Allow-Origin", "*")
                        self.send_header("Content-type", "application/json")
                        self.end_headers()
                        with open(filePath, "rb") as f:
                            self.wfile.write(f.read())
                    except socket.error as e:
                        if e.errno == errno.EPIPE:
                            print("Client disconnected before full response.")
                        else:
                            raise
                else:
                    self._send404()
            else:
                self._send404()

        def _send404(self):
            """Send a 404 response."""
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b"Resource not found.")

    return RequestHandler
