#!/usr/bin/env python3
"""van-sms-send — send an SMS through the EC25 modem from the command line.

Usage:
  van-sms-send <number> <text...>
  echo "message text" | van-sms-send <number>

The message is written to a temp file and passed via mmcli's
--messaging-create-sms-with-text (rather than inline in the "number=...,
text=..." properties string) — mmcli's properties-string parser breaks on
plain spaces/quotes/colons in inline text (found the hard way testing
van-sms-watch), the file form has none of that trouble.

Needs root: ModemManager's Messaging/Device.Control D-Bus actions are
PolicyKit-gated and unauthorized for a plain user session (read-only
actions like listing SMS work unprivileged; creating/sending don't). Run
with sudo.

Stdlib only.
"""

import json
import subprocess
import sys
import tempfile


def die(msg):
    print(f"van-sms-send: {msg}", file=sys.stderr)
    sys.exit(1)


def run_json(args):
    """Run mmcli with -J and return the parsed dict, dying on any failure."""
    try:
        out = subprocess.run(["mmcli", "-J", *args], capture_output=True,
                             text=True, timeout=20)
    except Exception as e:
        die(f"failed to run mmcli {' '.join(args)}: {e}")
    if out.returncode != 0:
        die(f"mmcli {' '.join(args)} failed: {out.stderr.strip() or out.stdout.strip()}")
    try:
        return json.loads(out.stdout)
    except Exception as e:
        die(f"mmcli {' '.join(args)} gave unparseable JSON ({e}): {out.stdout}")


def run_action(args):
    """Run mmcli for an action whose success is exit-code only (no JSON body
    even with -J, e.g. --send). Dies on failure."""
    try:
        out = subprocess.run(["mmcli", *args], capture_output=True, text=True, timeout=20)
    except Exception as e:
        die(f"failed to run mmcli {' '.join(args)}: {e}")
    if out.returncode != 0:
        die(f"mmcli {' '.join(args)} failed: {out.stderr.strip() or out.stdout.strip()}")


def find_modem():
    modems = run_json(["-L"]).get("modem-list") or []
    return modems[0] if modems else None


def main():
    if len(sys.argv) < 2:
        die("usage: van-sms-send <number> <text...>  (or pipe text on stdin)")
    number = sys.argv[1]
    if len(sys.argv) > 2:
        text = " ".join(sys.argv[2:])
    elif not sys.stdin.isatty():
        text = sys.stdin.read().rstrip("\n")
    else:
        die("no message text given as an argument or on stdin")
    if not text:
        die("message text is empty")

    modem = find_modem()
    if not modem:
        die("no modem found (mmcli -L found none)")

    with tempfile.NamedTemporaryFile("w", suffix=".txt") as f:
        f.write(text)
        f.flush()
        created = run_json(["-m", modem, f"--messaging-create-sms=number={number}",
                            f"--messaging-create-sms-with-text={f.name}"])

    sms_path = (created.get("modem") or {}).get("messaging", {}).get("created-sms")
    if not sms_path:
        die(f"couldn't find created SMS path in mmcli output: {created}")

    run_action(["-m", modem, "-s", sms_path, "--send"])
    print(f"sent to {number}: {text}")


if __name__ == "__main__":
    main()
