import json
import os
from typing import Any

import pytest
from dotenv import load_dotenv

import fabias
from fabias import (
    InitializationStrategy,
    ItemReference,
    PrincipalType,
    ReadWrite,
    RequiredAction,
    ServicePrincipalAuth,
    Variable,
    Workspace,
    WorkspaceRole,
)
from fabias._shared.exceptions import NotFoundError
from fabias.integrations import keyvault as secrets

# Load environment variables from .env file
load_dotenv()

_auth: ServicePrincipalAuth = None
_workspace: Workspace = None
_new_workspace: Workspace = None


@pytest.mark.integration
def test_authentication():
    global _auth
    _auth = ServicePrincipalAuth(
        tenant_id=os.getenv("AZURE_TENANT_ID"),
        client_id=os.getenv("AZURE_CLIENT_ID"),
        client_secret=os.getenv("AZURE_CLIENT_SECRET"),
    )

    secrets.client(vault_url=os.getenv("AZURE_KEYVAULT_URL"), auth=_auth)


@pytest.mark.integration
def test_workspace(skip=False):
    global _auth, _workspace

    if _auth is None:
        test_authentication()

    fabias.client(auth=_auth)

    _workspace = fabias.workspace(os.getenv("FABRIC_WORKSPACE_NAME"))

    if skip:
        return

    print(f"Workspace name: {_workspace.name}")
    for itm in _workspace.items():
        print(f" Item: {itm}")


@pytest.mark.integration
def test_list_workspaces():
    global _auth

    if _auth is None:
        test_authentication()

    fabias.client(auth=_auth)

    workspaces = fabias.workspaces()
    assert len(workspaces) > 0
    print(f"Found {len(workspaces)} workspaces:")
    for ws in workspaces:
        print(f" Workspace: {ws.name} (ID: {ws.id})")


@pytest.mark.integration
def test_connections():
    global _auth, _workspace

    if _auth is None:
        test_authentication()

    fabias.client(auth=_auth)

    # Test tenant-wide listing
    print("\n=== Tenant-wide connections ===")
    all_connections = fabias.connections()
    print(f"Found {len(all_connections)} connections")

    for conn in all_connections:
        print(f"  {conn.name}: {conn.connection_type} ({conn.connectivity_type})")

    # Test search by name
    search = os.getenv("FABRIC_CONNECTION_NAME")
    print(f"\n=== Search for connection by name: {search} ===")
    connection = fabias.connection(search)
    print(f"Found: {connection.name} (ID: {connection.id})")
    print(f"  Privacy Level: {connection.privacy_level}")
    print(f"  Connectivity: {connection.connectivity_type}")

    # Test lazy loading with GUID
    print("\n=== Test lazy loading ===")
    search_id = os.getenv("FABRIC_CONNECTION_ID")
    lazy_conn = fabias.connection(search_id)
    print(f"Created with GUID - ID available immediately: {lazy_conn.id}")
    print(f"Name not fetched yet (will trigger API call): {lazy_conn.name}")
    print(f"Subsequent access uses cached data: {lazy_conn.connectivity_type}")

    # Test refresh
    print("\n=== Test refresh ===")
    refreshed = lazy_conn.refresh()
    print(f"Refreshed: {refreshed.name}")

    # Test role assignments (nested resource pattern)
    print(f"\n=== Test role assignments for {lazy_conn.name} ===")
    try:
        # List all role assignments
        assignments = lazy_conn.role_assignments()
        print(f"Found {len(assignments)} role assignments")
        for assignment in assignments[:3]:  # Show first 3
            print(
                f"  {assignment.principal_name}: {assignment.role} (ID: {assignment.principal_id})"
            )

        # Test getting a specific role assignment (if any exist)
        if assignments:
            test_assignment = assignments[0]
            print(f"\n=== Get specific role assignment: {test_assignment.principal_id} ===")
            single_assignment = lazy_conn.role_assignment(test_assignment.principal_id)
            print(f"Retrieved: {single_assignment.principal_name} - {single_assignment.role}")
            print(f"  Principal Type: {single_assignment.principal_type}")
            print(f"  Principal ID: {single_assignment.principal_id}")

        # Note: Add/update/delete operations would be tested here
        # but require valid principal IDs and are destructive operations
        # Example (commented out for safety):
        new_role_id = os.getenv("FABRIC_GROUP_ID")
        print(f"\n=== Add role assignment: {new_role_id} ===")
        _ = lazy_conn.role_assignments.add(
            principal_id=new_role_id, principal_type="Group", role="User"
        )

        lazy_conn.refresh()
        assignments = lazy_conn.role_assignments()
        for assignment in assignments[:3]:  # Show first 3
            print(
                f"  {assignment.principal_name}: {assignment.role} (ID: {assignment.principal_id})"
            )

        print(f"\n=== Elevate role assignment: {new_role_id} ===")
        lazy_conn.role_assignments.update(new_role_id, "Owner")
        lazy_conn.refresh()
        assignments = lazy_conn.role_assignments()
        for assignment in assignments[:3]:  # Show first 3
            print(
                f"  {assignment.principal_name}: {assignment.role} (ID: {assignment.principal_id})"
            )

        print(f"\n=== Remove role assignment: {new_role_id} ===")
        lazy_conn.role_assignments.delete(new_role_id)
        lazy_conn.refresh()
        assignments = lazy_conn.role_assignments()
        for assignment in assignments[:3]:  # Show first 3
            print(
                f"  {assignment.principal_name}: {assignment.role} (ID: {assignment.principal_id})"
            )

    except Exception as e:
        print(f"Could not fetch role assignments: {e}")


@pytest.mark.integration
def test_fetch_workspace():
    global _workspace

    if _workspace is None:
        test_workspace(True)

    status = _workspace.git.status()
    print(f"\nGitStatus: {status}")

    connection = _workspace.git.connection()
    print(f"Workspace Git connection: {connection}")


@pytest.mark.integration
def test_create_workspace():
    global _auth, _new_workspace

    if _auth is None:
        test_authentication()

    fabias.client(auth=_auth)

    ws_name = os.getenv("FABRIC_ADD_WORKSPACE_NAME")
    Group_ID = os.getenv("FABRIC_GROUP_ID")
    print(f"\n=== Creating new workspace: {ws_name}")

    _new_workspace = fabias.workspaces.add(
        name=ws_name,
        capacity=os.getenv("FABRIC_CAPACITY_ID"),
        description="Test workspace created by fabias tests",
    )

    print(f"Created workspace: {_new_workspace.name} (ID: {_new_workspace.id})")

    try:
        # ===============
        # assignments
        # ===============
        assignments = _new_workspace.role_assignments()
        print(f"Found {len(assignments)} role assignments")
        for assignment in assignments[:5]:  # Show first 5
            print(
                f"  {assignment.principal_name or assignment.principal_id}: {assignment.role} ({assignment.principal_type})"
            )

        if Group_ID not in [a.principal_id for a in assignments]:
            print(f"\n=== Adding Admin Role to Group: {Group_ID}")
            new_assignment = _new_workspace.role_assignments.add(
                principal_id=Group_ID, principal_type=PrincipalType.GROUP, role=WorkspaceRole.ADMIN
            )
            print(
                f"  Role Added: {new_assignment.principal_name} (ID: {new_assignment.principal_id})"
            )

        # ==================
        # Git Configuration
        # ==================
        connection_id = os.getenv("FABRIC_CONNECTION_ID")
        print(f"\n=== Connecting to Git: {connection_id}")
        connect_operation = _new_workspace.git.connect(
            repository_url=os.getenv("FABRIC_GIT_URL"),
            branch=os.getenv("FABRIC_GIT_BRANCH_NAME"),
            directory=os.getenv("FABRIC_GIT_DIRECTORY"),
            connection=fabias.connection(connection_id),
        ).initialize(initialization_strategy=InitializationStrategy.PREFER_REMOTE)

        if connect_operation.is_immediate:
            print(f"  Remote commit: {connect_operation.remote_commit_hash}")
            print(f"  Workspace head: {connect_operation.workspace_head}")
            print(f"  Git initialization completed immediately: {connect_operation.status}")
            print(f"  Required action: {connect_operation.required_action}")

            if connect_operation.required_action == RequiredAction.UPDATE_FROM_GIT:
                print("  Updating workspace from Git...\n")
                connect_operation = _new_workspace.git.pull()

        print(f"Git initialization in progress (operation ID: {connect_operation.id})...")

        def printStatus(op: fabias.Operation):
            print(f" Operation status: {op.status} ({op.percent_complete}%)")

        connect_operation.wait(callback=printStatus)
        print(f"Git initialization completed: {connect_operation.status}")

    except Exception as e:
        print(f"Error testing workspace role assignments: {e}")
        import traceback

        traceback.print_exc()
        raise


@pytest.mark.integration
def test_delete_workspace():
    global _new_workspace

    if _new_workspace is None:
        test_create_workspace()

    print(f"\n=== Deleting workspace: {_new_workspace.name} (ID: {_new_workspace.id})")
    _new_workspace.delete()
    print("Workspace deleted.")


@pytest.mark.integration
def test_lakehouse_security():
    global _auth

    if _auth is None:
        test_authentication()

    fabias.client(auth=_auth)

    workspace = fabias.workspace(os.getenv("FABRIC_STORAGE_WORKSPACE_NAME"))

    print(f"\n=== Testing OneLake data access security in workspace: {workspace.name}")

    # First pass: Try to enable security on items that don't have it
    print("\n--- Phase 1: Checking security on lakehouses ---")
    lakehouses = workspace.lakehouses()

    from fabias import EntraMember, FabricItem, Role, Rule

    if len([lh for lh in lakehouses if not lh.securityEnabled]) == 0:
        print("  (All lakehouses already have security enabled)")

    else:
        print("  (Some lakehouses do not have security enabled)")

    # Second pass: List all roles for all lakehouses
    print("\n--- Phase 2: Roles of all lakehouses ---")
    enabled_count = 0
    disabled_count = 0

    permissions: list[dict[str, Any]] = json.loads(os.getenv("FABRIC_PERMISSIONS"))

    for lh in lakehouses:
        if lh.securityEnabled:
            enabled_count += 1
            roles = lh.accessRoles()
            print(f"\nLakehouse: {lh.name} (ID: {lh.id})")
            print("  Security: ✓ Enabled")
            print(f"  Roles ({len(roles)}):")
            for role in roles:
                print(f"    - {role.name} (ID: {role.id})")
                if lh.name == "Salesforce":
                    role._fetch()
                    print(f"\n  --- Raw JSON for role '{role.name}' ---")
                    print(json.dumps(role._data_raw, indent=2))

            payload: list[Role] = []
            for role in permissions:
                name = role.get("role")
                rules: dict = role.get("rules", {})
                items = role.get("fabricitems", [])
                members = role.get("entramembers", [])
                print(f"\n  -- adding role: '{name}'")
                # Create role with client context but no name (avoid fetch)
                rl = Role(
                    client=fabias._client,
                    workspace_id=lh.workspace_id,
                    item_id=lh.id,
                    rules=[
                        Rule(
                            paths=rules.get(
                                "Path", rules.get("path", ["*"])
                            ),  # Try capital P first, then lowercase
                            accessLevel=rules.get("permission", ReadWrite.READ),
                        )
                    ],
                )
                # Set name after construction to avoid fetch
                rl.name = name
                if items and len(items) > 0:
                    rl.members.append(FabricItem(access=items))  # Wrap in list
                if members and len(members) > 0:
                    for member in members:
                        rl.members.append(EntraMember(object=member))

                payload.append(rl)
                print(f"  -- Payload prepared for role: '{name}' with {len(rl.members)} members")
                print(json.dumps(rl.toJson(), indent=2))

            try:
                print(f"\n  --- Overwriting roles on lakehouse '{lh.name}' ---")
                lh.accessRoles.replace(payload)

                # Refresh and check if role was added
                lh.refreshAccessRoles()
                updated_roles = lh.accessRoles()
                for role in updated_roles:
                    print(f"    - {role.name} (ID: {role.id})")

            except Exception as e:
                print(f"  ✗ Failed to add role: {e}")
                if hasattr(e, "response_body"):
                    print(f"     Response: {e.response_body}")
        else:
            disabled_count += 1
            print(f"\nLakehouse: {lh.name} (ID: {lh.id})")
            print("  Security: ✗ Not enabled")

    print("\n--- Summary ---")
    print(f"Total lakehouses: {len(lakehouses)}")
    print(f"Security enabled: {enabled_count}")
    print(f"Security disabled: {disabled_count}")


@pytest.mark.integration
def test_notebook_definition():
    global _workspace

    if _workspace is None:
        test_workspace(True)

    notebook_name = os.getenv("FABRIC_NOTEBOOK_NAME")
    notebook = _workspace.notebook(notebook_name)
    print(
        f"\n=== Testing notebook definition retrieval for: {notebook.name} (ID: {notebook.id}) ==="
    )

    try:
        definition = notebook.definition
        print("Notebook definition retrieved successfully.")
        files = definition.files
        print("Decoded notebook files:")
        for file in files:
            print(f"  - {file.path}: {file.content[:100]}...")

    except Exception as e:
        print(f"Failed to retrieve notebook definition: {e}")


@pytest.mark.integration
def test_variable_libraries():
    global _auth

    if _auth is None:
        test_authentication()

    fabias.client(auth=_auth)
    workspace = fabias.workspace(os.getenv("VAR_WORKSPACE_NAME"))

    try:
        folder = workspace.folder("api_add")
        print(f"Found folder: {folder.name} (ID: {folder.id})")
    except NotFoundError:
        print("Folder 'api_add' not found. Creating it...")
        folder = workspace.folders.add(name="api_add")
        print(f"Created folder: {folder.name} (ID: {folder.id})")

    print(f"\n=== Testing variable library retrieval for workspace: {workspace.name} ===")
    try:
        lib_int = workspace.variableLibrary("var_int")
        print(f"Variable Library: {lib_int.name} (ID: {lib_int.id})")
    except NotFoundError:
        print("Variable Library 'var_int' not found. Creating it...")
        lib_int = workspace.variableLibraries.add(name="var_int", folder_id=folder.id)
        print(f"Created Variable Library: {lib_int.name} (ID: {lib_int.id})")

    try:
        lib_ext = workspace.variableLibrary("var_ext")
        print(f"Variable Library: {lib_ext.name} (ID: {lib_ext.id})")
    except NotFoundError:
        print("Variable Library 'var_ext' not found. Creating it...")
        lib_ext = workspace.variableLibraries.add(name="var_ext", folder_id=folder.id)
        print(f"Created Variable Library: {lib_ext.name} (ID: {lib_ext.id})")

    try:
        lib_prod = workspace.variableLibrary("var_prod")
        print(f"Variable Library: {lib_prod.name} (ID: {lib_prod.id})")
    except NotFoundError:
        print("Variable Library 'var_prod' not found. Creating it...")
        lib_prod = workspace.variableLibraries.add(name="var_prod", folder_id=folder.id)
        print(f"Created Variable Library: {lib_prod.name} (ID: {lib_prod.id})")

    # genesis_int = fabias.workspace(os.getenv("VAR_WORKSPACE_GEN_INT"))
    # genesis_ext = fabias.workspace(os.getenv("VAR_WORKSPACE_GEN_EXT"))
    # genesis_prod = fabias.workspace(os.getenv("VAR_WORKSPACE_GEN_PROD"))
    # nexus_int = fabias.workspace(os.getenv("VAR_WORKSPACE_NEX_INT"))
    # nexus_ext = fabias.workspace(os.getenv("VAR_WORKSPACE_NEX_EXT"))
    # nexus_prod = fabias.workspace(os.getenv("VAR_WORKSPACE_NEX_PROD"))

    parse_list: dict[str, Variable] = {}

    print("\n=== Parsing Items for workspace: GENESIS_INT ===")
    for lakehouse in fabias.workspace(os.getenv("VAR_WORKSPACE_GEN_INT")).lakehouses():
        print(
            f"Lakehouse: {lakehouse.name} (ID: {lakehouse.id}) in workspace {lakehouse.workspace_id}"
        )
        parse_list[lakehouse.name] = Variable(
            lakehouse.name, ItemReference(itemId=lakehouse.id, workspaceId=lakehouse.workspace_id)
        )

    print("\n=== Build var_int ===")
    print("May take a moment.  Building payload requires retrieving current structure...")
    for var in parse_list.values():
        lib_int.variables.add(var)
    for var in (v for v in lib_int.variables() if v.name not in parse_list):
        print(f"Removing stale variable: {var.name} (lakehouse no longer found)")
        lib_int.variables.remove(var.name)
    print(f"Prepared {len(parse_list)} variables for commit.")

    print("\n=== Committing ===")
    lib_int.variables.commit()
    print(f"Variable library '{lib_int.name}' updated with {len(lib_int.variables)} variables.")

    parse_list.clear()  # Clear for next workspace

    print("\n=== Parsing Items for workspace: GENESIS_EXT ===")
    for lakehouse in fabias.workspace(os.getenv("VAR_WORKSPACE_GEN_EXT")).lakehouses():
        print(
            f"Lakehouse: {lakehouse.name} (ID: {lakehouse.id}) in workspace {lakehouse.workspace_id}"
        )
        parse_list[lakehouse.name] = Variable(
            lakehouse.name, ItemReference(itemId=lakehouse.id, workspaceId=lakehouse.workspace_id)
        )

    print("\n=== Build var_ext ===")
    print("May take a moment.  Building payload requires retrieving current structure...")
    for var in parse_list.values():
        lib_ext.variables.add(var)
    for var in (v for v in lib_ext.variables() if v.name not in parse_list):
        print(f"Removing stale variable: {var.name} (lakehouse no longer found)")
        lib_ext.variables.remove(var.name)
    print(f"Prepared {len(parse_list)} variables for commit.")

    print("\n=== Committing ===")
    lib_ext.variables.commit()
    print(f"Variable library '{lib_ext.name}' updated with {len(lib_ext.variables)} variables.")

    parse_list.clear()  # Clear for next workspace

    print("\n=== Parsing Items for workspace: GENESIS ===")
    for lakehouse in fabias.workspace(os.getenv("VAR_WORKSPACE_GEN_PROD")).lakehouses():
        print(
            f"Lakehouse: {lakehouse.name} (ID: {lakehouse.id}) in workspace {lakehouse.workspace_id}"
        )
        parse_list[lakehouse.name] = Variable(
            lakehouse.name, ItemReference(itemId=lakehouse.id, workspaceId=lakehouse.workspace_id)
        )

    print("\n=== Build var_prod ===")
    print("May take a moment.  Building payload requires retrieving current structure...")
    for var in parse_list.values():
        lib_prod.variables.add(var)
    for var in (v for v in lib_prod.variables() if v.name not in parse_list):
        print(f"Removing stale variable: {var.name} (lakehouse no longer found)")
        lib_prod.variables.remove(var.name)
    print(f"Prepared {len(parse_list)} variables for commit.")

    print("\n=== Committing ===")
    lib_prod.variables.commit()
    print(f"Variable library '{lib_prod.name}' updated with {len(lib_prod.variables)} variables.")

    # varInt.variables._load()

    # print(f"\n\n=== Variable Details for Library: {varInt.name} ===")
    # print(json.dumps(varInt.variables._cache, indent=2, cls=_FabricEncoder))

    # print(f"\n\n=== Platform String for: {varInt.name} ===")
    # print(varInt.variables._platform)

    # print(f"\n\n=== Decoded Settings for: {varInt.name} ===")
    # print(json.dumps(varInt.variables._settings, indent=2))
    # varInt.variables.add(Variable(name="newVar", type="String", value="defaultValue", overrides={"Production": "prodValue"}))

    # print(f"\n\n=== Payload for commit on: {varInt.name} ===")
    # varInt.variables.commit()
    # varInt.variables._load()


@pytest.mark.integration
@pytest.mark.integration
def test_spark_settings():
    global _auth

    if _auth is None:
        test_authentication()

    fabias.client(auth=_auth)
    workspace = fabias.workspace(os.getenv("VAR_WORKSPACE_NAME"))

    print(f"\n=== Spark settings for workspace: {workspace.name} ===")

    # --- Read current settings ---
    s = workspace.spark.settings
    print(f"Before: {s!r}")
    print(f"  log                          : {s.log}")
    print(f"  highconcurrency.interactive  : {s.highconcurrency.interactive}")
    print(f"  highconcurrency.pipelines    : {s.highconcurrency.pipelines}")
    print(f"  environment.name             : {s.environment.name}")
    print(f"  environment.version          : {s.environment.version}")
    print(f"  pool.customcompute           : {s.pool.customcompute}")
    print(f"  pool.default.name            : {s.pool.default.name}")
    print(f"  pool.default.type            : {s.pool.default.type}")
    print(f"  pool.starter.nodes           : {s.pool.starter.nodes}")
    print(f"  pool.starter.executors       : {s.pool.starter.executors}")
    print(f"  jobs.reservecores            : {s.jobs.reservecores}")
    print(f"  jobs.timeout                 : {s.jobs.timeout}")

    # Capture originals for restore
    orig_log = s.log
    orig_interactive = s.highconcurrency.interactive
    orig_pipelines = s.highconcurrency.pipelines
    orig_env_name = s.environment.name
    orig_env_version = s.environment.version
    orig_customcompute = s.pool.customcompute
    orig_default_name = s.pool.default.name
    orig_default_type = s.pool.default.type
    orig_starter_nodes = s.pool.starter.nodes
    orig_starter_executors = s.pool.starter.executors
    orig_jobs_reservecores = s.jobs.reservecores
    orig_jobs_timeout = s.jobs.timeout

    # --- Mutate and commit ---
    print("\n=== Updating Spark settings ===")
    s.log = True
    s.highconcurrency.interactive = True
    s.pool.customcompute = True
    s.pool.starter.nodes = 10
    s.pool.starter.executors = 5
    # job settings — conservativeJobAdmissionEnabled is a plain bool (always present)
    if orig_jobs_reservecores is not None:
        s.jobs.reservecores = True
    if orig_jobs_timeout is not None:
        s.jobs.timeout = 30
    # pipelineRunEnabled only on higher SKUs
    if orig_pipelines is not None:
        s.highconcurrency.pipelines = True

    s.commit()
    print(f"After:  {s!r}")
    print(f"  log                          : {s.log}")
    print(f"  highconcurrency.interactive  : {s.highconcurrency.interactive}")
    print(f"  highconcurrency.pipelines    : {s.highconcurrency.pipelines}")
    print(f"  environment.name             : {s.environment.name}")
    print(f"  environment.version          : {s.environment.version}")
    print(f"  pool.customcompute           : {s.pool.customcompute}")
    print(f"  pool.default.name            : {s.pool.default.name}")
    print(f"  pool.default.type            : {s.pool.default.type}")
    print(f"  pool.starter.nodes           : {s.pool.starter.nodes}")
    print(f"  pool.starter.executors       : {s.pool.starter.executors}")
    print(f"  jobs.reservecores            : {s.jobs.reservecores}")
    print(f"  jobs.timeout                 : {s.jobs.timeout}")

    assert s.log is True
    assert s.highconcurrency.interactive is True
    assert s.pool.customcompute is True
    assert s.pool.starter.nodes == 10
    assert s.pool.starter.executors == 5
    if orig_jobs_reservecores is not None:
        assert s.jobs.reservecores is True

    input("\n>>> Paused — verify changes in browser, then press Enter to restore...")

    # --- Restore originals ---
    print("\n=== Restoring Spark settings ===")
    s.log = orig_log
    s.highconcurrency.interactive = orig_interactive
    s.highconcurrency.pipelines = orig_pipelines
    if orig_env_name is not None:
        s.environment.name = orig_env_name
        s.environment.version = orig_env_version
    s.pool.customcompute = orig_customcompute
    if orig_default_name is not None:
        s.pool.default.name = orig_default_name
        s.pool.default.type = orig_default_type
    s.pool.starter.nodes = orig_starter_nodes
    s.pool.starter.executors = orig_starter_executors
    if orig_jobs_reservecores is not None:
        s.jobs.reservecores = orig_jobs_reservecores
        s.jobs.timeout = orig_jobs_timeout
    s.commit()
    print(f"Restored: {s!r}")
    print("Spark settings test complete.")


@pytest.mark.integration
def test_activity_events():
    """Verify that activityEvents() returns events for a full calendar day."""
    from datetime import datetime, timedelta, timezone

    _auth = ServicePrincipalAuth(
        tenant_id=os.getenv("AZURE_TENANT_ID"),
        client_id=os.getenv("AZURE_CLIENT_ID"),
        client_secret=os.getenv("AZURE_CLIENT_SECRET"),
    )
    fabias.client(auth=_auth)

    # Audit log is available with up to ~30 day retention; use yesterday to ensure
    # data exists regardless of when the test runs.
    yesterday = (datetime.now(timezone.utc) - timedelta(days=1)).replace(
        hour=0, minute=0, second=0, microsecond=0
    )
    start = yesterday
    end = yesterday.replace(hour=23, minute=59, second=59)

    print(f"\n=== Fetching activity events: {start.date()} ===")
    events = fabias.tenant().activityEvents(start=start, end=end)

    print(f"Total events: {len(events)}")
    assert isinstance(events, list), "Expected a list of ActivityEvent objects"

    if not events:
        print("  (No events found for this period — tenant may have low activity)")
        return

    # Spot-check first few events
    for evt in events[:5]:
        print(f"  {evt.creation_time}  {evt.operation:<40}  {evt.user_id}")

    # Verify basic structure of every event
    for evt in events:
        assert evt.id is not None, "ActivityEvent missing Id"
        assert evt.operation is not None, "ActivityEvent missing Operation"

    # Operation breakdown
    from collections import Counter

    counts = Counter(evt.operation for evt in events)
    print("\nTop operations:")
    for op, n in counts.most_common(10):
        print(f"  {n:>6}  {op}")

    # Optional: filter to a specific operation if env var is set
    filter_op = os.getenv("FABRIC_AUDIT_OPERATION")
    if filter_op:
        print(f"\n=== Filtered events: Activity eq '{filter_op}' ===")
        filtered = fabias.tenant().activityEvents(
            start=start,
            end=end,
            filter=f"Activity eq '{filter_op}'",
        )
        print(f"  {len(filtered)} events matched")
        for evt in filtered[:5]:
            print(f"  {evt.creation_time}  {evt.workspace_name}  {evt.item_name}")
