#!/usr/bin/env python3
# Copyright 2026 (c) o6 Automation GmbH
"""
Client Configuration
====================

Walks through the configuration surface of ``o6.Client``. Every
property the client cares about (endpoint URL, request timeout,
session name, application identity, security settings, …) lives on
the ``ClientConfig`` object returned by ``client.config`` and can be
read and (in most cases) written through Python attribute
access.

The key rule this example demonstrates: **all writes to
``client.config`` must happen before the client is connected**. The
SDK raises ``RuntimeError`` if you try to mutate a field while the
session is active.

This example talks to the same address space as the other high-level
examples, served by ``S03_firststeps.py``.
"""


import os

import socket
import o6
from o6 import LocalizedText
from o6.ns import ns0

EXAMPLE_PORT = int(os.environ.get("O6_EXAMPLE_PORT", "4840"))
EXAMPLE_ENDPOINT = f"opc.tcp://localhost:{EXAMPLE_PORT}"


print("--- 1. Inspect the Default Configuration ---")
localhost = "localhost"
endpoint_url = EXAMPLE_ENDPOINT
print(f"Connecting to {endpoint_url} ...")

with o6.Client(endpoint_url) as client:
    cfg = client.config

    print(f"endpoint_url              = {cfg.endpointUrl!r}")
    print(f"timeout (ms)              = {cfg.timeout}")
    print(f"session_name              = {cfg.sessionName!r}")
    print(f"application_uri           = {cfg.applicationUri!r}")
    print(f"secure_channel_life_time  = {cfg.secureChannelLifeTime} ms")
    print(f"requested_session_timeout = {cfg.requestedSessionTimeout} ms")
    print(f"max_async_service_calls   = {cfg.maxAsyncServiceCalls}")
    print(f"no_session                = {cfg.noSession}")
    print(f"no_reconnect              = {cfg.noReconnect}")
    print(f"security_mode             = {cfg.securityMode}")
    print(f"security_policy           = {cfg.securityPolicy!r}")


print()
print("--- 2. Configure Before You Connect ---")
with o6.Client(endpoint_url) as client:
    cfg = client.config
    try:
        cfg.timeout = 1234
    except RuntimeError as e:
        print(f"Error: {e}")


print()
print("--- 3. Set Scalar Fields Before Connecting ---")
client = o6.Client(endpoint_url)
client.config.timeout = 1234  # milliseconds
client.config.sessionName = "hmi-client-1"  # shown in the server's session list
client.config.secureChannelLifeTime = 300_000  # 5 minutes
client.config.maxAsyncServiceCalls = 128  # concurrent calls; 0 disables the limit

print(f"timeout                  = {client.config.timeout}")
print(f"session_name             = {client.config.sessionName!r}")
print(f"secure_channel_life_time = {client.config.secureChannelLifeTime}")
print(f"max_async_service_calls  = {client.config.maxAsyncServiceCalls}")

with client as c:
    cfg = c.config
    print(f"timeout (connected)      = {cfg.timeout}")


print()
print("--- 4. Set the Application Identity ---")
client = o6.Client(endpoint_url)
cfg = client.config

ApplicationDescription = ns0.datatypes.ApplicationDescription
ApplicationType = ns0.datatypes.ApplicationType

desc = ApplicationDescription()
desc.applicationUri = "urn:example:o6:demo-client"
desc.applicationName = LocalizedText("o6 Demo Client")
desc.applicationType = ApplicationType.CLIENT
desc.productUri = "urn:example:o6"

cfg.applicationDescription = desc

print(f"application_uri  = {cfg.applicationDescription.applicationUri!r}")
print(f"application_name = {cfg.applicationDescription.applicationName!r}")
print(f"application_type = {cfg.applicationDescription.applicationType}")
print(f"product_uri      = {cfg.applicationDescription.productUri!r}")

with client as c:
    cfg = c.config
    print(f"application_description (connected) = {cfg.applicationDescription}")


print()
print("--- 5. Constructor and client.config ---")
with o6.Client(
    endpoint_url,
    applicationUri="urn:example:o6:demo-client",
) as client:
    cfg = client.config
    print(f"endpoint_url    = {cfg.endpointUrl!r}")
    print(f"application_uri = {cfg.applicationUri!r}")

    value = client.read("ns=1;i=1004")  # Plant / Counter
    print(f"Counter = {value}")

print()
print("=== Example completed ===")