import argparse
import json
import subprocess
import sys
import time
from datetime import datetime, timezone
from pathlib import Path
from urllib import request, error


def getUtcTimestamp():
    return datetime.now(timezone.utc).isoformat()


def extractJson(output):
    start = output.find("{")
    end = output.rfind("}")

    if start == -1 or end == -1 or end <= start:
        raise ValueError(f"No JSON object found in CLI output:\n{output}")

    return json.loads(output[start:end + 1])


def runThermoproCli(cliPath):
    command = [
        sys.executable,
        str(cliPath),
        "temps",
        "--json",
    ]

    result = subprocess.run(
        command,
        capture_output=True,
        text=True,
        check=False,
    )

    combinedOutput = "\n".join(
        part for part in [result.stdout, result.stderr] if part.strip()
    )

    if result.returncode != 0:
        raise RuntimeError(
            f"thermopro_cli.py exited with code {result.returncode}:\n{combinedOutput}"
        )

    return extractJson(combinedOutput)


def normalizeReading(rawReading, deviceId, macAddress):
    temperatures = rawReading.get("temperatures", [])
    probeNames = rawReading.get("probe_names", [])
    probeCount = rawReading.get("probe_count", len(temperatures))

    probes = []

    for index in range(probeCount):
        rawTemperature = temperatures[index] if index < len(temperatures) else -999.0
        name = probeNames[index] if index < len(probeNames) else f"Probe {index + 1}"
        isConnected = rawTemperature != -999.0

        probes.append({
            "id": index + 1,
            "name": name,
            "temperature": rawTemperature if isConnected else None,
            "connected": isConnected,
        })

    return {
        "deviceId": deviceId,
        "device": "ThermoPro TP930",
        "mac": macAddress,
        "connected": bool(rawReading.get("connected", False)),
        "battery": rawReading.get("battery"),
        "unit": rawReading.get("unit"),
        "probeCount": probeCount,
        "probes": probes,
        "readingTime": rawReading.get("last_update"),
        "bridgeTime": getUtcTimestamp(),
        "source": "thermopro_cli",
    }


def postReading(endpoint, token, payload):
    body = json.dumps(payload).encode("utf-8")

    headers = {
        "Content-Type": "application/json",
        "User-Agent": "thermopro-bridge-poc/0.1",
    }

    if token:
        headers["X-Bridge-Token"] = token

    req = request.Request(
        endpoint,
        data=body,
        headers=headers,
        method="POST",
    )

    try:
        with request.urlopen(req, timeout=10) as response:
            responseBody = response.read().decode("utf-8")
            return response.status, responseBody
    except error.HTTPError as e:
        responseBody = e.read().decode("utf-8")
        raise RuntimeError(f"POST failed with HTTP {e.code}: {responseBody}") from e
    except error.URLError as e:
        raise RuntimeError(f"POST failed: {e}") from e


def main():
    parser = argparse.ArgumentParser(
        description="ThermoPro TP930 proof-of-concept bridge"
    )

    parser.add_argument(
        "--cli",
        default="thermopro_cli.py",
        help="Path to thermopro_cli.py",
    )

    parser.add_argument(
        "--endpoint",
        default="http://127.0.0.1:8000/api/thermopro/readings",
        help="API endpoint to POST readings to",
    )

    parser.add_argument(
        "--token",
        default="dev-secret",
        help="Shared token sent as X-Bridge-Token",
    )

    parser.add_argument(
        "--device-id",
        default="tp930-smoker",
        help="Stable ID for this thermometer/bridge",
    )

    parser.add_argument(
        "--mac",
        default="C9:48:1D:B1:E1:E7",
        help="ThermoPro BLE MAC address",
    )

    parser.add_argument(
        "--interval",
        type=int,
        default=15,
        help="Polling interval in seconds",
    )

    parser.add_argument(
        "--once",
        action="store_true",
        help="Read and POST once, then exit",
    )

    args = parser.parse_args()
    cliPath = Path(args.cli)

    if not cliPath.exists():
        print(f"Could not find {cliPath}", file=sys.stderr)
        sys.exit(1)

    while True:
        try:
            rawReading = runThermoproCli(cliPath)
            payload = normalizeReading(rawReading, args.device_id, args.mac)
            status, responseBody = postReading(args.endpoint, args.token, payload)

            connectedProbes = [
                probe for probe in payload["probes"] if probe["connected"]
            ]

            print(
                f"[{payload['bridgeTime']}] POST {status} - "
                f"battery={payload['battery']}%, "
                f"connected_probes={len(connectedProbes)}"
            )

            print(json.dumps(payload, indent=2))

            if responseBody.strip():
                print(responseBody)

        except Exception as e:
            print(f"[{getUtcTimestamp()}] ERROR: {e}", file=sys.stderr)

        if args.once:
            break

        time.sleep(args.interval)


if __name__ == "__main__":
    main()
