import logging

from flask import Flask, redirect, request, url_for
from werkzeug.wrappers import Response

from planemapper.provisioning import ProvisioningError, airspace, config, location, tiles, wifi

log = logging.getLogger(__name__)

app = Flask(__name__)


def _build_form_html(
    error: str = "",
    resolved_name: str = "",
    resolved_lat: str = "",
    resolved_lon: str = "",
    radius: str = "100",
) -> str:
    error_html = f'<p style="color:red">{error}</p>' if error else ""
    confirmed_html = ""
    hidden_fields = ""
    if resolved_name:
        confirmed_html = f"""
<div style="background:#f0f0f0;padding:8px;margin:8px 0">
  <strong>Confirmed:</strong> {resolved_name}<br>
  Lat: {resolved_lat}, Lon: {resolved_lon}
</div>"""
        hidden_fields = f"""
  <input type="hidden" name="confirmed_lat" value="{resolved_lat}">
  <input type="hidden" name="confirmed_lon" value="{resolved_lon}">
  <input type="hidden" name="confirmed_name" value="{resolved_name}">"""
    return f"""<!DOCTYPE html>
<html>
<head><title>planeMapper Setup</title></head>
<body>
<h1>planeMapper Setup</h1>
{error_html}
<form method="POST" action="/find-location">
  <label>Location (ICAO code or address/postcode):<br>
    <input type="text" name="location" required>
  </label><br><br>
  <label>Coverage radius (nm):<br>
    <input type="number" name="radius" value="{radius}" min="10" max="500">
  </label><br><br>
  <button type="submit">Find location</button>
</form>
{confirmed_html}
<hr>
<form method="POST" action="/submit">
  {hidden_fields}
  <label>Home WiFi SSID:<br>
    <input type="text" name="wifi_ssid" required>
  </label><br><br>
  <label>Home WiFi password:<br>
    <input type="password" name="wifi_password" required>
  </label><br><br>
  <button type="submit">Set up device</button>
</form>
</body>
</html>"""


@app.route("/")
def index() -> str:
    return _build_form_html()


@app.route("/find-location", methods=["POST"])
def find_location() -> str:
    query = request.form.get("location", "").strip()
    radius = request.form.get("radius", "100")
    error_msg = ""
    resolved_name = ""
    resolved_lat = ""
    resolved_lon = ""
    if query:
        try:
            lat, lon, name = location.resolve(query)
            resolved_lat = str(lat)
            resolved_lon = str(lon)
            resolved_name = name
        except ValueError as e:
            error_msg = str(e)
    return _build_form_html(
        error=error_msg,
        resolved_name=resolved_name,
        resolved_lat=resolved_lat,
        resolved_lon=resolved_lon,
        radius=radius,
    )


@app.route("/generate_204")
@app.route("/hotspot-detect.html")
@app.route("/ncsi.txt")
def captive_redirect() -> Response:
    return redirect(url_for("index"))


@app.errorhandler(404)
def catch_all(e: Exception) -> Response:
    return redirect(url_for("index"))


def _run_provisioning(
    confirmed_lat: float,
    confirmed_lon: float,
    radius: float,
    wifi_ssid: str,
    wifi_password: str,
) -> str:
    wifi.join_home_wifi(wifi_ssid, wifi_password)
    tiles.download_and_composite(confirmed_lat, confirmed_lon, radius)
    airspace.download(confirmed_lat, confirmed_lon, radius)
    try:
        tiles.validate_cache()
    except ProvisioningError as e:
        log.error("cache validation failed: %s", e)
        return (
            f"<html><body><p>Cache validation failed: {e}. "
            f"<a href='/'>Try again</a></p></body></html>"
        )
    config.write(
        {
            "home_lat": confirmed_lat,
            "home_lon": confirmed_lon,
            "coverage_radius_nm": int(radius),
            "wifi_ssid": wifi_ssid,
            "wifi_password": wifi_password,
            "provisioned": True,
        }
    )
    wifi.kill_wifi()
    return (
        "<html><body>"
        "<h1>Setup complete. The device will now start displaying radar.</h1>"
        "</body></html>"
    )


@app.route("/submit", methods=["POST"])
def submit() -> str:
    try:
        confirmed_lat = float(request.form["confirmed_lat"])
        confirmed_lon = float(request.form["confirmed_lon"])
        confirmed_name = request.form.get("confirmed_name", "")
        radius = float(request.form.get("radius", "100"))
        wifi_ssid = request.form["wifi_ssid"]
        wifi_password = request.form["wifi_password"]
    except (KeyError, ValueError) as e:
        return f"<html><body><p>Invalid form data: {e}. <a href='/'>Try again</a></p></body></html>"

    log.info(
        "provisioning started for %s (%.4f, %.4f) r=%.0fnm",
        confirmed_name,
        confirmed_lat,
        confirmed_lon,
        radius,
    )
    result = _run_provisioning(confirmed_lat, confirmed_lon, radius, wifi_ssid, wifi_password)
    return result
