"""
Constants and type definitions for RDF models.

This module contains XSD datatype IRIs and module-level constants
used throughout the ORM layer.
"""

from enum import StrEnum


class XSD(StrEnum):
    """XSD datatype IRIs (full IRI form to avoid PREFIX dependency).

    Members are ``str`` instances so they can be passed directly as the
    ``datatype`` argument of :class:`LiteralField`.
    """

    STRING = "http://www.w3.org/2001/XMLSchema#string"
    INTEGER = "http://www.w3.org/2001/XMLSchema#integer"
    DECIMAL = "http://www.w3.org/2001/XMLSchema#decimal"
    FLOAT = "http://www.w3.org/2001/XMLSchema#float"
    DOUBLE = "http://www.w3.org/2001/XMLSchema#double"
    BOOLEAN = "http://www.w3.org/2001/XMLSchema#boolean"
    DATE = "http://www.w3.org/2001/XMLSchema#date"
    DATETIME = "http://www.w3.org/2001/XMLSchema#dateTime"


# Convenience aliases for backward compatibility and shorter usage
XSD_STRING: str = XSD.STRING
XSD_INTEGER: str = XSD.INTEGER
XSD_DECIMAL: str = XSD.DECIMAL
XSD_FLOAT: str = XSD.FLOAT
XSD_DOUBLE: str = XSD.DOUBLE
XSD_BOOLEAN: str = XSD.BOOLEAN
XSD_DATE: str = XSD.DATE
XSD_DATETIME: str = XSD.DATETIME

# Property path validation regex pattern (private; used only by PropertyPath)
_PROPERTY_PATH_ALLOWED_CHARS_PATTERN: str = (
    r"^[a-zA-Z0-9:\/\#\-\_\.\*\+\?\|\^\/\(\)\<\>\s]+$"
)

# Suffix for language tag variables in SPARQL queries (e.g., "name" -> "name_lang")
LANG_VARIABLE_SUFFIX: str = "_lang"

# Predicate marker for SubjectField (which doesn't represent a real predicate)
_SUBJECT_FIELD_PREDICATE_MARKER: str = "__subject__"

# RDF type predicate IRI
RDF_TYPE: str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"

# Default separator for GROUP_CONCAT aggregation
# Uses three ASCII Unit Separator characters (\u001F) which are:
# 1. Invisible in output (easier to work with than visible separators)
# 2. Guaranteed not to appear in natural text (control character)
# 3. Used in sequence of three to further reduce collision risk
DEFAULT_COLLECTION_SEPARATOR: str = "\u001f\u001f\u001f"

# Separator between value and metadata within collection items
# Uses ASCII Record Separator (\u001E) to combine value + separator + metadata
# Used by LangStringList (text + lang) and TypedLiteralList (value + datatype)
# This ensures value and metadata stay paired during GROUP_CONCAT aggregation
VALUE_METADATA_SEPARATOR: str = "\u001e"

# Aliases for backwards compatibility and semantic clarity
LANG_VALUE_SEPARATOR: str = VALUE_METADATA_SEPARATOR
DATATYPE_VALUE_SEPARATOR: str = VALUE_METADATA_SEPARATOR

# Suffix for GROUP_CONCAT result variables (e.g., "labels" -> "labels_concat")
COLLECTION_CONCAT_SUFFIX: str = "_concat"

# Suffix for SAMPLE() result variables in collection queries
# Avoids SPARQL variable scope conflicts (e.g., "description" -> "description_sample")
SAMPLE_VARIABLE_SUFFIX: str = "_sample"


def _escape_sparql_string(value: str) -> str:
    """
    Escape a string value for use in SPARQL query.

    Handles backslashes, double quotes, and control characters (U+0000-U+001F)
    which have special meaning or are invalid in SPARQL string literals.
    Control characters are emitted as SPARQL Unicode escape sequences (\\uXXXX).

    Args:
        value: String value to escape

    Returns:
        Escaped string safe for use in SPARQL literals
    """
    result: str = value.replace("\\", "\\\\").replace('"', '\\"')
    return "".join(f"\\u{ord(c):04X}" if ord(c) < 0x20 else c for c in result)


__all__ = [
    "XSD",
    "XSD_STRING",
    "XSD_INTEGER",
    "XSD_DECIMAL",
    "XSD_FLOAT",
    "XSD_DOUBLE",
    "XSD_BOOLEAN",
    "XSD_DATE",
    "XSD_DATETIME",
    "RDF_TYPE",
    "LANG_VARIABLE_SUFFIX",
    "DEFAULT_COLLECTION_SEPARATOR",
    "VALUE_METADATA_SEPARATOR",
    "LANG_VALUE_SEPARATOR",
    "DATATYPE_VALUE_SEPARATOR",
    "COLLECTION_CONCAT_SUFFIX",
    "SAMPLE_VARIABLE_SUFFIX",
    "_escape_sparql_string",
    "_PROPERTY_PATH_ALLOWED_CHARS_PATTERN",
    "_SUBJECT_FIELD_PREDICATE_MARKER",
]
