#!/usr/bin/python3
import subprocess
import os
import sys
import json
import shutil
import threading
import gc
import time


def _valid_json_file(path):
    try:
        with open(path, encoding="utf-8-sig") as f:
            return isinstance(json.load(f), dict)
    except Exception:
        return False

def _ensure_config():
    """
    Create default config files on first run if they don't exist.
    This lets the web UI load even before the user has configured anything.
    """
    base_dir = os.path.dirname(os.path.abspath(__file__))
    cfg_dir  = os.path.join(base_dir, "config")
    os.makedirs(cfg_dir, exist_ok=True)

    cfg_path = os.path.join(cfg_dir, "config.json")
    sec_path = os.path.join(cfg_dir, "secrets.json")
    cfg_backup = cfg_path + ".bak"
    sec_backup = sec_path + ".bak"

    default_cfg = {
        "location": {
            "zone_home": {
                "tl_y": 41.953371,
                "tl_x": -87.746000,
                "br_y": 41.889507,
                "br_x": -87.623695
            },
            "location_home": [41.926550, -87.695440],
            "temperature_location": "41.926550,-87.695440",
            "temperature_units": "imperial",
            "distance_units": "imperial",
            "speed_units": "imperial",
            "clock_format": "12hr",
            "journey_code": "ORD",
            "journey_blank_filler": " ? "
        },
        "display": {
            "brightness": 100,
            "brightness_night": 50,
            "night_brightness": False,
            "panel_count": 2,
            "night_start": "22:00",
            "night_end": "06:00",
            "gpio_slowdown": 2,
            "hat_pwm_enabled": True,
            "forecast_days": 3
        },
        "flights": {
            "min_altitude": 2600,
            "max_altitude": 100000,
            "max_display_flights": 5,
            "max_farthest": 3,
            "max_closest": 3,
            "email": ""
        },
        "master_slave": {
            "master_tracker": "",
            "other_tracker_hostnames": []
        },
        "route_cache": {
            "enabled": True,
            "days": 30
        },
        "quiet_time": {
            "enabled": False,
            "start": "23:00",
            "end": "06:00",
            "weather_interval_seconds": 3600
        },
        "updates": {
            "enabled": False,
            "manifest_url": "",
            "check_on_start": True,
            "auto_install": True,
            "timeout_seconds": 20,
            "keep_backups": 2
        },
        "position_sources": {
            "order": ["OpenSky"],
            "poll_seconds": 120,
            "enabled": {
                "OpenSky": True
            }
        },
        "api_sources": {
            "order": ["FlightStats", "AirLabs", "FlightAware", "FR24Unofficial", "FR24"],
            "enabled": {
                "FlightStats": True,
                "AirLabs": True,
                "FlightAware": True,
                "FR24Unofficial": False,
                "FR24": False
            }
        },
        "display_fields": {
            "flight_details": ["airline", "flight_number"],
            "plane_details": ["plane", "home_distance", "direction", "altitude", "vertical_speed"]
        },
        "sports": {
            "enabled": True,
            "priority": ["mlb", "nfl", "nba", "nhl", "mls",
                         "college_football", "college_basketball", "epl"],
            "teams": {},
            "cycle_seconds": 10
        }
    }

    default_sec = {
        "tomorrow_api_key": "",
        "opensky_client_id": "",
        "opensky_client_secret": "",
        "airlabs_api_keys": [],
        "flightaware_api_keys": [],
        "flightaware_monthly_limit": 4.00,
        "flightradar24_key": "",
        "moon_key": ""
    }

    if not _valid_json_file(cfg_path) and _valid_json_file(cfg_backup):
        shutil.copy2(cfg_backup, cfg_path)
        print("[Setup] Restored config/config.json from backup")

    if not _valid_json_file(sec_path) and _valid_json_file(sec_backup):
        shutil.copy2(sec_backup, sec_path)
        print("[Setup] Restored config/secrets.json from backup")

    if not _valid_json_file(cfg_path):
        with open(cfg_path, "w") as f:
            json.dump(default_cfg, f, indent=2)
        print("[Setup] Created default config/config.json — edit via web UI at :8080/config")

    if not _valid_json_file(sec_path):
        with open(sec_path, "w") as f:
            json.dump(default_sec, f, indent=2)
        print("[Setup] Created default config/secrets.json — add your API keys via web UI at :8080/config")


if __name__ == "__main__":
    base_dir = os.path.dirname(os.path.abspath(__file__))

    # Ensure config files exist before anything else loads
    _ensure_config()

    startup_display = None
    try:
        from utilities.startup_status import StartupStatus
        from utilities.updater import prepare_startup, startup_update

        startup_display = StartupStatus()
        startup_display.show("Starting", 0)
        startup_prepare = prepare_startup(progress=startup_display.show)
        if startup_prepare.get("rolled_back"):
            startup_display.show("Restarting previous version", 100)
            startup_display.close()
            os.execv(sys.executable, [sys.executable, os.path.abspath(__file__)])
        update_result = startup_update(progress=startup_display.show)
        if update_result.get("installed"):
            startup_display.show("Restarting updated app", 100)
            startup_display.close()
            os.execv(sys.executable, [sys.executable, os.path.abspath(__file__)])
        startup_display.show("Starting display", 100)
        time.sleep(5)
    except Exception as e:
        print(f"[Updater] Startup check failed: {e}")
    finally:
        if startup_display is not None:
            startup_display.close()
            startup_display = None
            gc.collect()

    # Build path to web/app.py
    app_path = os.path.join(base_dir, "web", "app.py")

    # Start Flask server in background
    subprocess.Popen(["python3", app_path])

    # Give NetworkManager time to reconnect to a saved Wi-Fi network. If it
    # cannot, start a temporary setup access point without delaying the display.
    def _start_wifi_setup_if_needed():
        try:
            from utilities.wifi_setup_mode import ensure_setup_ap_if_offline
            result = ensure_setup_ap_if_offline(wait_seconds=35)
            print(f"[WiFiSetup] {result.get('message', '')}")
            if result.get("active"):
                print(
                    f"[WiFiSetup] Join {result.get('ssid')} with password "
                    f"{result.get('password')} then open {result.get('url')}"
                )
        except Exception as e:
            print(f"[WiFiSetup] Could not start setup mode: {e}")

    threading.Thread(target=_start_wifi_setup_if_needed, daemon=True).start()

    # Start display loop
    from display import Display
    run_text = Display()
    try:
        from utilities.updater import mark_app_started
        mark_app_started()
    except Exception as e:
        print(f"[Updater] Could not mark startup healthy: {e}")
    run_text.run()
