#!/usr/bin/env python3
"""
Python LLRP Inventory Gateway Daemon
Connects to standard EPCglobal LLRP fixed readers (Impinj Speedway, Zebra FX9600)
over TCP port 5084, streams RO_ACCESS_REPORT tags, debounces duplicates, and
forwards clean event batches to custom ERP/WMS webhooks.
"""

import sys
import time
import logging
import argparse
import requests
from twisted.internet import reactor
from sllurp import llrp
from sllurp.llrp import LLRPClientFactory

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("LLRPGateway")

class LlrpInventoryGateway:
    def __init__(self, host: str, port: int, webhook_url: str, debounce_sec: float = 3.0):
        self.host = host
        self.port = port
        self.webhook_url = webhook_url
        self.debounce_sec = debounce_sec
        self.seen_tags = {}  # epc -> last_seen_timestamp

    def tag_report_cb(self, llrpc, tag_reports):
        now = time.time()
        new_tags = []

        for report in tag_reports:
            epc = report.get("EPC-96") or report.get("EPCData")
            rssi = report.get("PeakRSSI", -60.0)
            antenna = report.get("AntennaID", 1)

            if not epc:
                continue

            last_seen = self.seen_tags.get(epc, 0)
            if (now - last_seen) > self.debounce_sec:
                self.seen_tags[epc] = now
                new_tags.append({"epc": epc, "rssi": rssi, "antenna": antenna, "timestamp": int(now * 1000)})
                logger.info(f"Tag Detected: EPC={epc} | Ant={antenna} | RSSI={rssi} dBm")

        if new_tags and self.webhook_url:
            self.forward_to_webhook(new_tags)

    def forward_to_webhook(self, tags):
        try:
            payload = {"reader": self.host, "count": len(tags), "tags": tags}
            resp = requests.post(self.webhook_url, json=payload, timeout=3.0)
            logger.info(f"Dispatched {len(tags)} tags to webhook. HTTP {resp.status_code}")
        except Exception as e:
            logger.error(f"Failed to forward tags to webhook: {e}")

    def run(self):
        logger.info(f"Connecting to LLRP reader at {self.host}:{self.port}...")
        factory = LLRPClientFactory(
            on_finish=lambda: reactor.stop(),
            tag_content_selector={
                "EnableROSpecID": False,
                "EnableSpecIndex": False,
                "EnableInventoryParameterSpecID": False,
                "EnableAntennaID": True,
                "EnableChannelIndex": False,
                "EnablePeakRSSI": True,
                "EnableFirstSeenTimestamp": True,
                "EnableLastSeenTimestamp": True,
                "EnableTagSeenCount": True,
                "EnableAccessSpecID": False,
            }
        )
        factory.add_tag_report_callback(self.tag_report_cb)
        reactor.connectTCP(self.host, self.port, factory, timeout=10)
        reactor.run()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Python LLRP RFID Gateway")
    parser.add_argument("--host", default="192.168.1.100", help="LLRP Reader IP address")
    parser.add_argument("--port", type=int, default=5084, help="LLRP TCP port (default 5084)")
    parser.add_argument("--webhook", default="", help="HTTP Webhook URL to dispatch clean tags")
    parser.add_argument("--debounce", type=float, default=3.0, help="Debounce cooldown window in seconds")
    args = parser.parse_args()

    gateway = LlrpInventoryGateway(args.host, args.port, args.webhook, args.debounce)
    gateway.run()
