#!/usr/bin/env python3
"""
sms_sender.py — Swing Shift Twilio SMS dispatcher

Usage:
  python3 13_Scripts/sms_sender.py --to "+16025551234" --template slow_day --vars '{"promo_code":"SWING15","discount":"15"}'
  python3 13_Scripts/sms_sender.py --to "+16025551234" --template booking_confirm --vars '{"date":"Thu Mar 20","time":"2:00 PM"}'

Requires env vars:
  TWILIO_ACCOUNT_SID
  TWILIO_AUTH_TOKEN
  TWILIO_FROM_NUMBER   (your Twilio phone number, e.g. +18005551234)

All sends require approval before going live (approval_required=True by default).
Set --force to bypass for internal/test sends only.
"""

import os
import sys
import json
import argparse
import urllib.request
import urllib.parse
import base64
from datetime import datetime
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent

# ── SMS Templates ──────────────────────────────────────────────────────────────

TEMPLATES = {
    "slow_day": (
        "Swing Shift: Open bays today! Use {promo_code} for {discount}% off any session. "
        "Book now: theswingshift.golf/book — Reply STOP to opt out."
    ),
    "win_back": (
        "Hey, it's Swing Shift. Miss your game? Use {promo_code} for {discount}% off — "
        "valid {expiry}. Book: theswingshift.golf/book — Reply STOP to opt out."
    ),
    "booking_confirm": (
        "Swing Shift: You're booked! {date} at {time}. "
        "Paradise Valley, AZ. Questions? Reply here or call us. See you soon."
    ),
    "membership_renewal": (
        "Swing Shift: Your membership renews soon. Keep unlimited access & priority booking — "
        "renew at theswingshift.golf/membership — Reply STOP to opt out."
    ),
    "welcome": (
        "Welcome to Swing Shift Golf Club! We're glad you're here. "
        "Book your first session at theswingshift.golf/book — Reply STOP to opt out."
    ),
}

# ── Approval log ───────────────────────────────────────────────────────────────

APPROVAL_LOG = ROOT / "ops" / "approvals" / "pending"


def log_pending_approval(to: str, template: str, rendered: str) -> Path:
    """Write an approval record and return the file path."""
    ts = datetime.now().strftime("%Y-%m-%d-%H%M%S")
    fname = APPROVAL_LOG / f"{ts}-sms-{template}.md"
    APPROVAL_LOG.mkdir(parents=True, exist_ok=True)
    fname.write_text(
        f"---\n"
        f"type: sms_send\n"
        f"status: pending\n"
        f"created: {datetime.now().isoformat()}\n"
        f"---\n\n"
        f"**Action:** Send SMS via Twilio\n"
        f"**Target:** {to}\n"
        f"**Template:** {template}\n"
        f"**Message:**\n\n> {rendered}\n\n"
        f"**Risk:** Outbound SMS to customer. Irreversible once sent.\n"
    )
    return fname


# ── Twilio send ────────────────────────────────────────────────────────────────

def send_sms(to: str, body: str) -> dict:
    """Send SMS via Twilio REST API using only stdlib."""
    sid = os.environ.get("TWILIO_ACCOUNT_SID")
    token = os.environ.get("TWILIO_AUTH_TOKEN")
    from_number = os.environ.get("TWILIO_FROM_NUMBER")

    if not all([sid, token, from_number]):
        raise EnvironmentError(
            "Missing Twilio credentials. Set TWILIO_ACCOUNT_SID, "
            "TWILIO_AUTH_TOKEN, and TWILIO_FROM_NUMBER in your environment."
        )

    url = f"https://api.twilio.com/2010-04-01/Accounts/{sid}/Messages.json"
    data = urllib.parse.urlencode({"To": to, "From": from_number, "Body": body}).encode()
    credentials = base64.b64encode(f"{sid}:{token}".encode()).decode()

    req = urllib.request.Request(
        url, data=data,
        headers={"Authorization": f"Basic {credentials}",
                 "Content-Type": "application/x-www-form-urlencoded"},
        method="POST"
    )
    try:
        with urllib.request.urlopen(req) as resp:
            return json.loads(resp.read())
    except urllib.error.HTTPError as e:
        body_err = e.read().decode()
        raise RuntimeError(f"Twilio error {e.code}: {body_err}") from e


# ── Bulk send ──────────────────────────────────────────────────────────────────

def send_bulk(numbers, template, vars_,
              dry_run=True, force=False):
    """Send to a list of numbers. dry_run=True just prints, force bypasses approval."""
    tmpl = TEMPLATES.get(template)
    if not tmpl:
        raise ValueError(f"Unknown template: {template}. Valid: {list(TEMPLATES)}")

    results = []
    for number in numbers:
        rendered = tmpl.format(**vars_)
        if dry_run:
            print(f"[DRY RUN] TO={number}\n  {rendered}\n")
            results.append({"to": number, "status": "dry_run"})
            continue

        if not force:
            approval_file = log_pending_approval(number, template, rendered)
            print(f"[PENDING APPROVAL] {approval_file}")
            results.append({"to": number, "status": "pending_approval",
                            "approval_file": str(approval_file)})
            continue

        result = send_sms(number, rendered)
        print(f"[SENT] TO={number} SID={result.get('sid')} status={result.get('status')}")
        results.append({"to": number, "sid": result.get("sid"),
                        "status": result.get("status")})

    return results


# ── CLI ────────────────────────────────────────────────────────────────────────

def main():
    parser = argparse.ArgumentParser(description="Swing Shift SMS sender")
    parser.add_argument("--to", required=True, help="E.164 phone number, e.g. +16025551234")
    parser.add_argument("--template", required=True, choices=list(TEMPLATES),
                        help="Message template name")
    parser.add_argument("--vars", default="{}", help="JSON dict of template variables")
    parser.add_argument("--dry-run", action="store_true", default=True,
                        help="Print message without sending (default: on)")
    parser.add_argument("--force", action="store_true", default=False,
                        help="Send immediately, bypassing approval queue (use carefully)")
    args = parser.parse_args()

    vars_ = json.loads(args.vars)
    template = TEMPLATES.get(args.template, "")
    rendered = template.format(**vars_)

    if args.force:
        dry_run = False
    else:
        dry_run = args.dry_run

    results = send_bulk([args.to], args.template, vars_, dry_run=dry_run, force=args.force)
    print(json.dumps(results, indent=2))


if __name__ == "__main__":
    main()
