from http import HTTPStatus
from flask import Flask, Response, request, send_file
from os import urandom
from threading import Thread, Event
from werkzeug.serving import make_server
from typing import Optional
from types import FrameType
import signal
import sys
from base64 import b64encode as base64_encode

SERVER_IP: str = "0.0.0.0"
HTTP_HOST: str = "sniphbank.com"
HTTP_PORT: int = 80
HTTPS_PORT: int = 443
DEBUG: bool = False

app = Flask(__name__)
app.secret_key = urandom(24)


@app.route("/")
def index():
    return send_file("./website/index.html")


@app.route("/login", methods=["POST"])
def login():
    # There isn't really a reason to validate the user for the demo,
    # just decide on a username that might pertain to whomever's
    # personal information

    user = request.form["username"]
    password = request.form["password"].encode()

    if user != "ronniej":
        return Response("User not found", HTTPStatus.UNAUTHORIZED)
    if base64_encode(password).decode() != "Z29GQUxDT05TMTIzCg==":
        return Response("Incorrect password", HTTPStatus.UNAUTHORIZED)

    return send_file("./website/account.html")


@app.route("/css/style.css", methods=["GET"])
def stylesheet():
    return send_file("./website/css/style.css")


@app.route("/favicon.ico", methods=["GET"])
def favicon():
    return send_file("./website/favicon.ico")


class ServerThread(Thread):
    def __init__(
        self,
        app: Flask,
        host: str,
        port: int,
        ssl_context: Optional[tuple[str, str]] = None,
        name: str = "ServerThread",
    ) -> None:
        super().__init__(name=name, daemon=True)
        self.server = make_server(
            host,
            port,
            app,
            threaded=True,
            ssl_context=ssl_context,  # tuple (cert, key) or SSLContext
        )

    def run(self):
        self.server.serve_forever()

    def shutdown(self):
        self.server.shutdown()


def _install_signal_handlers(stop_event: Event):
    def handler(signum: signal.Signals, frame: Optional[FrameType]):
        stop_event.set()

    signal.signal(signal.SIGINT, handler)
    try:
        signal.signal(signal.SIGTERM, handler)
    except AttributeError:
        pass


if __name__ == "__main__":
    stop_event = Event()
    _install_signal_handlers(stop_event)

    http_server = ServerThread(
        app, SERVER_IP, HTTP_PORT, ssl_context=None, name="HTTP-Thread"
    )
    https_server = ServerThread(
        app,
        SERVER_IP,
        HTTPS_PORT,
        ssl_context=("./certs/cert.pem", "./certs/key.pem"),
        name="HTTPS-Thread",
    )

    try:
        http_server.start()
        https_server.start()
        print(f"HTTP  server running at http://{SERVER_IP}:{HTTP_PORT}")
        print(f"HTTPS server running at https://{SERVER_IP}:{HTTPS_PORT}")
        print("Press Ctrl+C to stop.")
        stop_event.wait()
    except KeyboardInterrupt:
        pass
    finally:
        for srv in (http_server, https_server):
            try:
                srv.shutdown()
            except Exception:
                pass

        for srv in (http_server, https_server):
            srv.join(timeout=5)

        print("Servers stopped!")
        sys.exit(0)
