#!/usr/bin/env python3
"""Test auto-reply functionality by sending LXMF message to styrene-node.

This script:
1. Initializes local RNS/LXMF (TCP-only to avoid port conflicts)
2. Waits for styrene-node to announce (or uses cached identity)
3. Sends a test message
4. Waits for auto-reply
5. Reports results

Usage:
    python scripts/test_auto_reply.py
"""

import asyncio
import logging
import os
import sys
import tempfile
import time
from pathlib import Path

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)

# styrene-node q502l identity
# The full 64-byte identity key (32 private + 32 public) - needed to create destination
# This is from /home/styrene/.styrene/operator.key on the q502l
STYRENE_NODE_KEY_HEX = "98064789910ee026de9b346154a820c8c3a14775ffbbc808b8cf1a1a53ebb067ba9a72179bea3228e855f90de2cf59b6e8c1c3d9eb2b66c9fe2d85910f8836bf"
# Derived hashes:
#   Identity hash: 698f2232d4ddab456ca11f38c8bb8a90
#   lxmf.delivery destination: f3e11839bf683643

# Create temp directory for test artifacts
TEST_DIR = tempfile.mkdtemp(prefix="lxmf_test_")
LXMF_STORAGE = os.path.join(TEST_DIR, "lxmf")
RNS_CONFIG_DIR = os.path.join(TEST_DIR, "reticulum")


def create_test_rns_config() -> str:
    """Create a test RNS config that uses only TCP (no AutoInterface).

    This avoids port conflicts with running RNS instances.
    """
    os.makedirs(RNS_CONFIG_DIR, exist_ok=True)
    config_path = os.path.join(RNS_CONFIG_DIR, "config")

    config_content = """\
# Test RNS config - TCP only (no AutoInterface to avoid conflicts)

[reticulum]
enable_transport = false
share_instance = false

[interfaces]

[[Styrene Hub TCP]]
type = TCPClientInterface
enabled = true
target_host = 192.168.0.102
target_port = 4242
"""
    Path(config_path).write_text(config_content)
    logger.info(f"Created test RNS config at {config_path}")
    return RNS_CONFIG_DIR


async def main() -> int:
    """Run auto-reply test."""
    try:
        import LXMF
        import RNS
    except ImportError:
        logger.error("RNS/LXMF not installed. Run: pip install rns lxmf")
        return 1

    # Create isolated RNS config for test (TCP only)
    config_path = create_test_rns_config()

    logger.info(f"Initializing RNS with config: {config_path}...")
    reticulum = RNS.Reticulum(configdir=config_path)

    # Wait for TCP connection to hub
    logger.info("Waiting for TCP connection to hub...")
    await asyncio.sleep(5)

    # Check interface status
    for interface in RNS.Transport.interfaces:
        logger.info(
            f"Interface: {interface.name} - online={getattr(interface, 'online', 'N/A')}"
        )

    # Create our identity for sending
    logger.info("Creating local identity...")
    identity = RNS.Identity()

    # Initialize LXMF router
    logger.info(f"Initializing LXMF router (storage: {LXMF_STORAGE})...")
    router = LXMF.LXMRouter(identity=identity, storagepath=LXMF_STORAGE)

    # Track received messages
    received_messages: list[tuple[str, str]] = []

    def message_callback(message: LXMF.LXMessage) -> None:
        """Handle incoming LXMF message."""
        source = message.source_hash.hex()
        content = message.content.decode("utf-8") if message.content else ""
        logger.info(f"Received message from {source[:16]}...")
        logger.info(f"Content: {content}")
        received_messages.append((source, content))

    router.register_delivery_callback(message_callback)

    # Wait for hub connection
    logger.info("Waiting for network to stabilize (10s)...")
    await asyncio.sleep(10)

    # Load styrene-node identity directly from known key
    # This bypasses the need to wait for announce/recall
    logger.info("Loading styrene-node identity from known key...")
    key_bytes = bytes.fromhex(STYRENE_NODE_KEY_HEX)

    # Write key to temp file and load as identity
    key_file = os.path.join(TEST_DIR, "styrene_node.key")
    with open(key_file, "wb") as f:
        f.write(key_bytes)

    dest_identity = RNS.Identity.from_file(key_file)
    logger.info(f"Loaded identity: {dest_identity.hexhash[:16]}...")

    # Create destination
    dest = RNS.Destination(
        dest_identity,
        RNS.Destination.OUT,
        RNS.Destination.SINGLE,
        LXMF.APP_NAME,
        "delivery",
    )

    # Create source destination
    source_dest = RNS.Destination(
        identity,
        RNS.Destination.OUT,
        RNS.Destination.SINGLE,
        LXMF.APP_NAME,
        "delivery",
    )

    # Create and send test message
    test_content = f"Hello from auto-reply test! Time: {time.strftime('%H:%M:%S')}"
    logger.info(f"Sending test message: {test_content}")
    logger.info(f"Destination hash: {dest.hexhash}")

    message = LXMF.LXMessage(
        destination=dest,
        source=source_dest,
        content=test_content.encode("utf-8"),
        fields={"protocol": "chat"},
    )

    # Track message delivery status
    def delivery_callback(message: LXMF.LXMessage) -> None:
        state_names = {
            LXMF.LXMessage.GENERATING: "GENERATING",
            LXMF.LXMessage.OUTBOUND: "OUTBOUND",
            LXMF.LXMessage.SENDING: "SENDING",
            LXMF.LXMessage.SENT: "SENT",
            LXMF.LXMessage.DELIVERED: "DELIVERED",
            LXMF.LXMessage.FAILED: "FAILED",
        }
        state = state_names.get(message.state, f"UNKNOWN({message.state})")
        logger.info(f"Message state changed: {state}")

    message.register_delivery_callback(delivery_callback)

    router.handle_outbound(message)
    logger.info("Message queued for delivery...")

    # Wait for auto-reply (up to 30 seconds)
    for i in range(6):
        await asyncio.sleep(5)
        if received_messages:
            logger.info("=" * 60)
            logger.info("AUTO-REPLY RECEIVED!")
            logger.info("=" * 60)
            for source, content in received_messages:
                logger.info(f"From: {source[:16]}...")
                logger.info(f"Content:\n{content}")
            logger.info("=" * 60)
            logger.info("TEST PASSED!")
            return 0
        logger.info(f"Waiting for reply... ({(i + 1) * 5}s)")

    logger.error("No auto-reply received within 30 seconds")
    logger.error("TEST FAILED")
    return 1


if __name__ == "__main__":
    sys.exit(asyncio.run(main()))
