"""Shared field value type aliases, conversion helpers, and common dataclasses."""
from dataclasses import dataclass
from datetime import date, datetime, time
from typing import TypeVar

DmsObjectFieldValueTypes = str | int | date | datetime | time | float | None
DmsObjectFieldValueTypesT = TypeVar("DmsObjectFieldValueTypesT", bound=DmsObjectFieldValueTypes)


def dms_object_field_value_to_str(value: DmsObjectFieldValueTypes) -> str:
    """Convert a DMS field value to its server-side string representation."""
    if isinstance(value, datetime):  # must precede date check — datetime is a subclass of date
        return value.strftime("%d.%m.%Y %H:%M:%S")
    if isinstance(value, date):
        return value.strftime("%d.%m.%Y")
    if isinstance(value, time):
        return value.strftime("%H:%M:%S")
    if isinstance(value, bool):
        return "1" if value else "0"
    return str(value)


@dataclass(frozen=True)
class ECMDocumentDigest:
    """Digest values for a document object returned by ``std.GetDocumentDigest``.

    Attributes:
        table_digest: Digest value stored in the database (always present).
        local_digest: Freshly calculated digest value. Only populated when
            ``calculate=True`` was passed to ``ECMDmsSync.digest()`` /
            ``ECMDmsAsync.digest()``.
    """

    table_digest: str
    local_digest: str | None


def maintype_from_type_id(object_type_id: int) -> int:
    """Extract the main type (lower 32 bits) from a combined object type ID."""
    return object_type_id & 0xFFFFFFFF


def cotype_from_type_id(object_type_id: int) -> int:
    """Extract the co-type (upper 32 bits) from a combined object type ID."""
    return (object_type_id >> 32) & 0xFFFFFFFF
