"""SOAP envelope builder for Ross1000 Regione Liguria integration.

Wraps a plain Ross1000 XML payload in a SOAP 1.1 envelope compatible with:
    https://turismows.regione.liguria.it/ws/checkinV2?wsdl

The envelope structure follows SOAP 1.1 (SOAPAction header required by the
Liguria endpoint). The inner payload is the same XML generated by
movement_serializer.py, embedded as the body content.

Live transmission is NOT implemented — this module only builds the envelope.
A future transport client should:
1. Call build_soap_envelope(xml_payload)
2. POST the result to the WSDL endpoint with Content-Type: text/xml
3. Include SOAPAction header as required by the WSDL operation
"""

from __future__ import annotations

from io import BytesIO
from xml.etree import ElementTree

from istat.ross1000.soap.schemas import (
    ROSS1000_NS,
    SOAP_ENV_NS,
    WS_SECURITY_NS,
)

# Register namespace prefixes for clean output
ElementTree.register_namespace("soapenv", SOAP_ENV_NS)
ElementTree.register_namespace("tur", ROSS1000_NS)


def build_soap_envelope(
    xml_payload: str,
    *,
    operation: str = "inviaMovimenti",
    username: str = "",
    password: str = "",
) -> str:
    """Wrap a Ross1000 XML payload in a SOAP 1.1 envelope.

    Args:
        xml_payload: The plain Ross1000 XML string (from movement_serializer)
        operation:   WSDL operation name (default: "inviaMovimenti")
        username:    Optional ISTAT credential username (for WS-Security header)
        password:    Optional ISTAT credential password (for WS-Security header)

    Returns:
        UTF-8 SOAP envelope XML string ready for HTTP POST.

    Note:
        Credentials are included in the SOAP Header only when both username
        and password are non-empty. For now this is a placeholder — the
        actual authentication scheme must be confirmed against the WSDL.
    """
    # Build envelope — namespace prefixes are registered globally above;
    # do NOT set xmlns:* attributes manually or ElementTree will duplicate them.
    envelope = ElementTree.Element(f"{{{SOAP_ENV_NS}}}Envelope")

    # Header (optional credentials)
    header = ElementTree.SubElement(envelope, f"{{{SOAP_ENV_NS}}}Header")
    if username and password:
        _add_wssecurity_header(header, username=username, password=password)

    # Body
    body = ElementTree.SubElement(envelope, f"{{{SOAP_ENV_NS}}}Body")
    operation_el = ElementTree.SubElement(body, f"{{{ROSS1000_NS}}}{operation}")

    # Embed the raw XML payload as a text node inside the operation element
    # The WSDL expects the movimento XML as the body of the operation call.
    payload_el = ElementTree.SubElement(operation_el, "payload")
    payload_el.text = xml_payload

    return _to_utf8_xml(envelope)


def _add_wssecurity_header(
    header: ElementTree.Element,
    *,
    username: str,
    password: str,
) -> None:
    """Add a WS-Security UsernameToken to the SOAP header.

    This is a placeholder implementation. The actual WS-Security scheme
    (UsernameToken, digest, nonce, etc.) must be confirmed against the
    Regione Liguria WSDL before live transmission.
    """
    ElementTree.register_namespace("wsse", WS_SECURITY_NS)

    security = ElementTree.SubElement(header, f"{{{WS_SECURITY_NS}}}Security")
    token = ElementTree.SubElement(security, f"{{{WS_SECURITY_NS}}}UsernameToken")

    user_el = ElementTree.SubElement(token, f"{{{WS_SECURITY_NS}}}Username")
    user_el.text = username

    pass_el = ElementTree.SubElement(token, f"{{{WS_SECURITY_NS}}}Password")
    pass_el.text = password


def _to_utf8_xml(root: ElementTree.Element) -> str:
    """Serialize an ElementTree to a UTF-8 XML string with declaration."""
    tree = ElementTree.ElementTree(root)
    buf = BytesIO()
    tree.write(buf, encoding="UTF-8", xml_declaration=True, short_empty_elements=False)
    return buf.getvalue().decode("UTF-8")
