"""What the recipes share: arguments, connecting, printing values and test documents."""

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from mfiles_client import MFilesClient  # noqa: E402
from mfiles_values import boolean, lookup, named_acl, property_value, text  # noqa: E402

from mfiles import IRPCObjectOperations_pb2 as ops  # noqa: E402
from mfiles import IRPCObjectOperations_pb2_grpc  # noqa: E402
from mfiles import structs_pb2 as structs  # noqa: E402

CLIENT_NAME = "M-Files gRPC recipes"  # The client name the recipes log in with.
TEST_PREFIX = "[docs-test]"           # Titles of objects the recipes create start with this.


def connect() -> MFilesClient:
    """Connects and logs in with the MFILES_* settings."""
    return MFilesClient.from_env(CLIENT_NAME)


def _positional() -> list:
    return [arg for arg in sys.argv[1:] if not arg.startswith("--")]


def int_arg(index: int, default: int) -> int:
    """The positional argument at ``index`` as an integer, or a default."""
    args = _positional()
    return int(args[index]) if index < len(args) else default


def string_arg(index: int, default: str = "") -> str:
    """The positional argument at ``index``, or a default."""
    args = _positional()
    return args[index] if index < len(args) else default


def keep() -> bool:
    """True when the caller asked to keep the objects the recipe creates (--keep)."""
    return "--keep" in sys.argv[1:]


def describe(item: structs.ObjectVersionEx) -> str:
    """One line about an object version, the same in every recipe."""
    version = item.version_info
    return (f"{version.title} (ID {item.object_info.obj_id.item_id.internal_id}, "
            f"version {version.version.internal_version}, "
            f"modified {version.last_modified_at_utc.ToDatetime():%Y-%m-%d %H:%M:%S} UTC)")


# [START format-value]
def format_value(value: structs.TypedValue) -> str:
    """A typed value as text: lookups show their names and IDs."""
    if value.is_null_value:
        return "(empty)"
    data = value.data
    kind = data.WhichOneof("data")  # The member of the oneof that is set.
    if kind in ("text", "multi_line_text", "integer", "integer64", "real_number",
                "decimal_number"):
        return str(getattr(data, kind))
    if kind == "boolean":
        return "yes" if data.boolean else "no"
    if kind == "date":  # Midnight UTC of the day.
        return f"{data.date.ToDatetime():%Y-%m-%d}"
    if kind == "timestamp":
        return f"{data.timestamp.ToDatetime():%Y-%m-%d %H:%M:%S} UTC"
    if kind == "lookup":
        return _format_lookup(data.lookup)
    if kind == "multi_select_lookup":
        return "; ".join(_format_lookup(item) for item in data.multi_select_lookup.values)
    return f"({value.type})"


def _format_lookup(item: structs.Lookup) -> str:
    info = item.value_list_item_info
    return f"{info.name} (ID {info.obj_id.item_id.internal_id})"
# [END format-value]


def create_test_document(client: MFilesClient, title: str,
                         *extra_properties: structs.PropertyValue) -> structs.ObjectVersionEx:
    """Creates a "[docs-test]" document of class "Other Document" (1) without files, for recipes
    that need an object to change."""
    objects = client.stub(IRPCObjectOperations_pb2_grpc.IRPCObjectOperationsStub)
    response = objects.AddObjectWithFiles(ops.AddObjectWithFilesRequest(
        object_type_id=0,
        properties=[
            property_value(0, text(f"{TEST_PREFIX} Python {title}")),  # Name or title
            property_value(100, lookup(1, 1)),                         # Class: Other Document
            property_value(22, boolean(False)),                        # Single file: no
            *extra_properties,
        ],
        # Named ACL -1, "Full control for all internal users". Without an ACL, not even the
        # creator could see the object.
        acl=named_acl(-1),
        check_in=True))
    return response.created_object.object_version


# [START delete-object]
def delete(client: MFilesClient, object_id: structs.ObjID) -> None:
    """Deletes an object the recipe created. Deleted objects can be undeleted; destroying one
    (DestroyObject) is final and needs more rights."""
    objects = client.stub(IRPCObjectOperations_pb2_grpc.IRPCObjectOperationsStub)
    objects.RemoveObject(ops.RemoveObjectRequest(obj_id=object_id))
    print(f"Deleted object {object_id.type}-{object_id.item_id.internal_id}")
# [END delete-object]
