#  Copyright 2026 Synnax Labs, Inc.
#
#  Use of this software is governed by the Business Source License included in the file
#  licenses/BSL.txt.
#
#  As of the Change Date specified in that file, in accordance with the Business Source
#  License, use of this software will be governed by the Apache License, Version 2.0,
#  included in the file licenses/APL.txt.

"""
This script connects to the OPC UA test server by registering it as a device in Synnax.

If the device is already connected, the script exits successfully.
Otherwise, it prompts to create a new OPC UA device connection automatically.

Before running this example:
1. Start the Synnax Driver (if not already running).

2. Start the OPC UA test server:
   uv run python -m examples.opcua.server

   For a TLS-encrypted server:
   uv run python -m examples.opcua.server --tls

3. Login to Synnax (if not already logged in):
   uv run sy login

4. Run this script:
   uv run python examples/opcua/connect_server.py

   For a TLS-encrypted server:
   uv run python examples/opcua/connect_server.py --tls

Configuration:
    Modify the constants below to match your OPC UA server configuration.
"""

import argparse
from pathlib import Path

import synnax as sy

# Certificate directory (auto-generated by the encrypted test server)
CERT_DIR = Path(__file__).parent / "certificates"

# Plain server config
PLAIN_DEVICE_NAME = "OPC UA Server"
PLAIN_ENDPOINT = "opc.tcp://127.0.0.1:4841/"

# TLS-encrypted server config
TLS_DEVICE_NAME = "OPC UA TLS Server"
TLS_ENDPOINT = "opc.tcp://127.0.0.1:4842/"

# TLS-encrypted + username/password server config
TLS_AUTH_DEVICE_NAME = "OPC UA TLS Auth Server"
TLS_AUTH_ENDPOINT = "opc.tcp://127.0.0.1:4843/"
TLS_AUTH_USERNAME = "testuser"
TLS_AUTH_PASSWORD = "testpass"

parser = argparse.ArgumentParser(description="Connect an OPC UA server to Synnax")
parser.add_argument(
    "--tls",
    action="store_true",
    help="Connect to the TLS-encrypted server (port 4842)",
)
parser.add_argument(
    "--tls-auth",
    action="store_true",
    help="Connect to the TLS-encrypted server with username/password (port 4843)",
)
args = parser.parse_args()

if args.tls_auth:
    DEVICE_NAME = TLS_AUTH_DEVICE_NAME
    ENDPOINT = TLS_AUTH_ENDPOINT
elif args.tls:
    DEVICE_NAME = TLS_DEVICE_NAME
    ENDPOINT = TLS_ENDPOINT
else:
    DEVICE_NAME = PLAIN_DEVICE_NAME
    ENDPOINT = PLAIN_ENDPOINT

# Connect to Synnax
client = sy.Synnax()

print("=" * 70)
print("OPC UA Server Connection Script")
print("=" * 70)
print(f"Target Device Name: {DEVICE_NAME}")
print(f"Endpoint: {ENDPOINT}")
if args.tls_auth:
    print("Security: Basic256Sha256 SignAndEncrypt + Username/Password")
elif args.tls:
    print("Security: Basic256Sha256 SignAndEncrypt")
print()

# Check if device already exists
existing_device = client.devices.retrieve(name=DEVICE_NAME, ignore_not_found=True)

if existing_device is not None:
    print("✓ Device already connected!")
    print(f"- Name: {existing_device.name}")
    print(f"- Key: {existing_device.key}")
    print(f"- Location: {existing_device.location}")
    print()
    print("No action needed - device is ready to use.")
    print("=" * 70)
    exit(0)

# Device not found - prompt user for connection method
print("Device not found")
print()
print("Would you like to connect automatically? [Y/N]: ", end="", flush=True)

try:
    response = input().strip().lower()
except (KeyboardInterrupt, EOFError):
    print("\n")
    response = "n"

if response in ("", "y", "yes"):
    print()
    print("Connecting to OPC UA server...")

    try:
        # Get the embedded rack (local driver rack)
        rack = client.racks.retrieve_embedded_rack()
        print(f"Using rack: {rack.name} (key={rack.key})")

        # Build device kwargs
        device_kwargs: dict = {
            "endpoint": ENDPOINT,
            "name": DEVICE_NAME,
            "location": ENDPOINT,
            "rack": rack.key,
        }

        if args.tls_auth or args.tls:
            device_kwargs.update(
                security_mode="SignAndEncrypt",
                security_policy="Basic256Sha256",
                server_cert=str(CERT_DIR / "server-certificate.der"),
                client_cert=str(CERT_DIR / "client-certificate.der"),
                client_private_key=str(CERT_DIR / "client-private-key.pem"),
            )
        if args.tls_auth:
            device_kwargs.update(
                username=TLS_AUTH_USERNAME,
                password=TLS_AUTH_PASSWORD,
            )

        device = sy.opcua.Device(**device_kwargs)
        created_device = client.devices.create(device)

        print("✓ Device connected successfully!")
        print(f"  - Name: {created_device.name}")
        print(f"  - Key: {created_device.key}")
        print(f"  - Location: {created_device.location}")
        print(f"  - Rack: {rack.name}")
        if args.tls_auth:
            print("  - Security: Basic256Sha256 SignAndEncrypt + Username/Password")
        elif args.tls:
            print("  - Security: Basic256Sha256 SignAndEncrypt")
        print()
        print("Device is ready to use.")
        print("=" * 70)
        exit(0)

    except Exception as e:
        print(f"✗ Failed to connect device: {e}")
        print()
        print("Please try connecting manually (see instructions below).")
        response = "n"  # Fall through to manual instructions

if response in ("n", "no") or response not in ("", "y", "yes"):
    # Manual connection instructions
    print()
    print("To connect manually:")
    print("1. Open the Synnax Console")
    print("2. Add a new OPC UA device:")
    print(f"   - Name: {DEVICE_NAME}")
    print(f"   - Endpoint: {ENDPOINT}")
    print("   - Make: opc")
    if args.tls:
        print("   - Security Mode: SignAndEncrypt")
        print("   - Security Policy: Basic256Sha256")
        print(f"   - Server Certificate: {CERT_DIR / 'server-certificate.der'}")
        print(f"   - Client Certificate: {CERT_DIR / 'client-certificate.der'}")
        print(f"   - Client Private Key: {CERT_DIR / 'client-private-key.pem'}")
    print("=" * 70)
    exit(1)
