# TESTING TOOL -- do not run this against a real home.
#
# Pushes plausible synthetic indoor/outdoor HVAC readings to an account at
# 5-minute spacing, so you can exercise a client (or watch an account leave
# the "defaults" schedule) without wiring up real hardware. Use a test
# account only -- this writes real readings to whatever account you log
# into.
#
# Spec: https://docs.hungrymachines.io/openapi.json
# Guide: https://docs.hungrymachines.io/guides/build-with-an-agent/
#
# Reads credentials from environment variables; never prints them.
#
#   HM_EMAIL           required -- test account email
#   HM_PASSWORD         required -- test account password
#   HM_APPLIANCE_ID     required -- an HVAC appliance already registered
#                       on that account (see hm_client.py's create_appliance)
#   HM_BASE_URL         optional -- defaults to https://api.hungrymachines.io
#
# Usage:
#   HM_EMAIL=... HM_PASSWORD=... HM_APPLIANCE_ID=... python3 simulate_readings.py --hours 6

import argparse
import math
import os
import sys
import time
from datetime import datetime, timedelta, timezone

from hm_client import DEFAULT_BASE_URL, HMAPIError, HMClient

READING_SPACING_MINUTES = 5


def synthetic_reading(appliance_id, at, elapsed_minutes):
    """A plausible HVAC reading: outdoor temperature follows a slow daily
    sine wave, indoor temperature drifts toward it while the unit cycles
    on and off around a 72F setpoint."""
    outdoor_temp = 78.0 + 10.0 * math.sin(elapsed_minutes / (24 * 60) * 2 * math.pi)
    cycle_on = (elapsed_minutes // 15) % 2 == 0
    indoor_temp = 72.0 + (1.5 if cycle_on else -1.0)
    return {
        "appliance_id": appliance_id,
        "timestamp": at.isoformat(),
        "indoor_temp": round(indoor_temp, 1),
        "outdoor_temp": round(outdoor_temp, 1),
        "hvac_state": "COOL" if cycle_on else "IDLE",
        "target_temp": 72.0,
    }


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument(
        "--hours", type=float, default=1.0, help="how many simulated hours of readings to push"
    )
    parser.add_argument(
        "--sleep",
        action="store_true",
        help="sleep in real time between readings instead of backdating timestamps",
    )
    args = parser.parse_args()

    email = os.environ.get("HM_EMAIL")
    password = os.environ.get("HM_PASSWORD")
    appliance_id = os.environ.get("HM_APPLIANCE_ID")
    base_url = os.environ.get("HM_BASE_URL", DEFAULT_BASE_URL)
    if not email or not password or not appliance_id:
        print(
            "Set HM_EMAIL, HM_PASSWORD and HM_APPLIANCE_ID (a test account only).",
            file=sys.stderr,
        )
        raise SystemExit(1)

    client = HMClient.log_in(email, password, base_url=base_url)

    total_minutes = int(args.hours * 60)
    now = datetime.now(timezone.utc)
    count = 0
    for elapsed in range(0, total_minutes, READING_SPACING_MINUTES):
        at = now if args.sleep else now - timedelta(minutes=total_minutes - elapsed)
        reading = synthetic_reading(appliance_id, at, elapsed)
        try:
            client.push_readings([reading])
        except HMAPIError as exc:
            print(f"push_readings failed: HTTP {exc.status}: {exc.detail}", file=sys.stderr)
            raise SystemExit(1) from None
        count += 1
        if args.sleep:
            time.sleep(READING_SPACING_MINUTES * 60)

    print(f"Pushed {count} synthetic readings for appliance {appliance_id}.")


if __name__ == "__main__":
    main()
