#!/usr/bin/env python3
"""
IoT Shield – Smart Door Lock Simulator

Generates intermittent access events for a smart door lock and forwards
them to Splunk Enterprise via HEC.
"""

import json
import random
import time
from datetime import datetime

import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------

DEVICE_ID = "door-lock-main"
DEVICE_TYPE = "smart_door_lock"
LOCATION = "main_entrance"

SPLUNK_HEC_URL = "https://192.168.1.247:8088/services/collector/event"
SPLUNK_TOKEN = "a6e5158e-8a7f-455c-aee8-c18d4102e476"

# Door locks are more sporadic: choose a random interval between events.
LOG_INTERVAL_MIN_SECONDS = 15
LOG_INTERVAL_MAX_SECONDS = 45

USERS = ["alice", "bob", "charlie", "admin", "unknown"]

HEADERS = {
    "Authorization": f"Splunk {SPLUNK_TOKEN}",
    "Content-Type": "application/json",
}


# ---------------------------------------------------------------------------
# Telemetry generation
# ---------------------------------------------------------------------------

def generate_lock_event() -> dict:
    """Generate a single smart door lock access event."""
    timestamp = datetime.now().isoformat()
    action = random.choice(["unlock", "lock", "access_attempt"])
    user = random.choice(USERS)

    # Unknown users always fail; known users succeed 90% of the time.
    if user == "unknown":
        success = False
    else:
        success = random.random() < 0.90

    lock_status = "locked"
    if action == "unlock" and success:
        lock_status = "unlocked"

    event = {
        "timestamp": timestamp,
        "device_id": DEVICE_ID,
        "device_type": DEVICE_TYPE,
        "location": LOCATION,
        "action": action,
        "user": user,
        "success": success,
        "battery_level": random.randint(70, 100),
        "lock_status": lock_status,
    }

    if not success:
        event["failure_reason"] = random.choice(
            ["invalid_pin", "wrong_fingerprint", "timeout"]
        )
        print(f"[WARN] Access denied – user={user}, reason={event['failure_reason']}")
    else:
        print(f"[INFO] {action.upper()} by user={user}")

    return event


# ---------------------------------------------------------------------------
# Splunk forwarding
# ---------------------------------------------------------------------------

def send_to_splunk(event_data: dict) -> None:
    """Send a single event to Splunk HEC."""
    payload = {
        "event": event_data,
        "sourcetype": "iot:doorlock",
        "index": "iot_devices",
    }

    try:
        response = requests.post(
            SPLUNK_HEC_URL,
            headers=HEADERS,
            json=payload,
            verify=False,
            timeout=5,
        )
        if response.status_code == 200:
            print(f"[INFO] Event sent from {event_data['device_id']}")
        else:
            print(f"[ERROR] HEC HTTP {response.status_code}: {response.text}")
    except Exception as exc:
        print(f"[ERROR] Exception while sending event: {exc}")


# ---------------------------------------------------------------------------
# Main loop
# ---------------------------------------------------------------------------

def main() -> None:
    """Run the door lock simulator indefinitely."""
    print("Starting smart door lock simulator")
    print(f"  Device ID  : {DEVICE_ID}")
    print(f"  HEC URL    : {SPLUNK_HEC_URL}")
    print(
        f"  Interval   : random {LOG_INTERVAL_MIN_SECONDS}–"
        f"{LOG_INTERVAL_MAX_SECONDS} seconds"
    )
    print("-" * 60)

    while True:
        try:
            event = generate_lock_event()
            print(json.dumps(event, indent=2))
            send_to_splunk(event)
            interval = random.randint(
                LOG_INTERVAL_MIN_SECONDS, LOG_INTERVAL_MAX_SECONDS
            )
            time.sleep(interval)
        except KeyboardInterrupt:
            print("\n[INFO] Stopping door lock simulator.")
            break
        except Exception as exc:
            print(f"[ERROR] Unexpected error in main loop: {exc}")
            time.sleep(LOG_INTERVAL_MIN_SECONDS)


if __name__ == "__main__":
    main()