# ruff: noqa: E402

"""
execute_api_request example

Requires a running OpenFGA server (default: http://localhost:8080).
    export FGA_API_URL=http://localhost:8080   # optional, this is the default
    python3 execute_api_request_example.py
"""

import asyncio
import os
import sys


sdk_path = os.path.realpath(os.path.join(os.path.abspath(__file__), "..", "..", ".."))
sys.path.insert(0, sdk_path)

from openfga_sdk import (
    ClientConfiguration,
    CreateStoreRequest,
    Metadata,
    ObjectRelation,
    OpenFgaClient,
    RelationMetadata,
    RelationReference,
    TypeDefinition,
    Userset,
    Usersets,
    WriteAuthorizationModelRequest,
)
from openfga_sdk.client.models import (
    ClientCheckRequest,
    ClientTuple,
    ClientWriteRequest,
)
from openfga_sdk.credentials import Credentials


async def main():
    api_url = os.getenv("FGA_API_URL", "http://localhost:8080")

    configuration = ClientConfiguration(
        api_url=api_url,
        credentials=Credentials(),
    )

    async with OpenFgaClient(configuration) as fga_client:
        print("=== Setup ===")

        store = await fga_client.create_store(
            CreateStoreRequest(name="execute_api_request_test")
        )
        fga_client.set_store_id(store.id)
        print(f"Created store: {store.id}")

        model_resp = await fga_client.write_authorization_model(
            WriteAuthorizationModelRequest(
                schema_version="1.1",
                type_definitions=[
                    TypeDefinition(type="user"),
                    TypeDefinition(
                        type="document",
                        relations=dict(
                            writer=Userset(this=dict()),
                            viewer=Userset(
                                union=Usersets(
                                    child=[
                                        Userset(this=dict()),
                                        Userset(
                                            computed_userset=ObjectRelation(
                                                object="", relation="writer"
                                            )
                                        ),
                                    ]
                                )
                            ),
                        ),
                        metadata=Metadata(
                            relations=dict(
                                writer=RelationMetadata(
                                    directly_related_user_types=[
                                        RelationReference(type="user"),
                                    ]
                                ),
                                viewer=RelationMetadata(
                                    directly_related_user_types=[
                                        RelationReference(type="user"),
                                    ]
                                ),
                            )
                        ),
                    ),
                ],
            )
        )
        auth_model_id = model_resp.authorization_model_id
        fga_client.set_authorization_model_id(auth_model_id)
        print(f"Created model: {auth_model_id}")

        await fga_client.write(
            ClientWriteRequest(
                writes=[
                    ClientTuple(
                        user="user:anne",
                        relation="writer",
                        object="document:roadmap",
                    ),
                ]
            )
        )
        print("Wrote tuple: user:anne writer document:roadmap")

        print("\n=== execute_api_request ===\n")

        # 1. ListStores
        print("1. ListStores (GET /stores)")
        raw = await fga_client.execute_api_request(
            operation_name="ListStores",
            method="GET",
            path="/stores",
            query_params={"page_size": 100},
        )
        sdk = await fga_client.list_stores()
        body = raw.json()
        assert raw.status == 200, f"Expected 200, got {raw.status}"
        assert "stores" in body
        assert len(body["stores"]) == len(sdk.stores)
        print(f"   {len(body['stores'])} stores (status {raw.status})")

        # 2. GetStore
        print("2. GetStore (GET /stores/{{store_id}})")
        raw = await fga_client.execute_api_request(
            operation_name="GetStore",
            method="GET",
            path="/stores/{store_id}",
            path_params={"store_id": store.id},
        )
        sdk = await fga_client.get_store()
        body = raw.json()
        assert raw.status == 200
        assert body["id"] == sdk.id
        assert body["name"] == sdk.name
        print(f"   id={body['id']}, name={body['name']}")

        # 3. ReadAuthorizationModels
        print(
            "3. ReadAuthorizationModels (GET /stores/{{store_id}}/authorization-models)"
        )
        raw = await fga_client.execute_api_request(
            operation_name="ReadAuthorizationModels",
            method="GET",
            path="/stores/{store_id}/authorization-models",
            path_params={"store_id": store.id},
        )
        sdk = await fga_client.read_authorization_models()
        body = raw.json()
        assert raw.status == 200
        assert len(body["authorization_models"]) == len(sdk.authorization_models)
        print(f"   {len(body['authorization_models'])} models")

        # 4. Check
        print("4. Check (POST /stores/{{store_id}}/check)")
        raw = await fga_client.execute_api_request(
            operation_name="Check",
            method="POST",
            path="/stores/{store_id}/check",
            path_params={"store_id": store.id},
            body={
                "tuple_key": {
                    "user": "user:anne",
                    "relation": "viewer",
                    "object": "document:roadmap",
                },
                "authorization_model_id": auth_model_id,
            },
        )
        sdk = await fga_client.check(
            ClientCheckRequest(
                user="user:anne",
                relation="viewer",
                object="document:roadmap",
            )
        )
        body = raw.json()
        assert raw.status == 200
        assert body["allowed"] == sdk.allowed
        print(f"   allowed={body['allowed']}")

        # 5. Read
        print("5. Read (POST /stores/{{store_id}}/read)")
        raw = await fga_client.execute_api_request(
            operation_name="Read",
            method="POST",
            path="/stores/{store_id}/read",
            path_params={"store_id": store.id},
            body={
                "tuple_key": {
                    "user": "user:anne",
                    "object": "document:",
                },
            },
        )
        body = raw.json()
        assert raw.status == 200
        assert "tuples" in body
        assert len(body["tuples"]) >= 1
        print(f"   {len(body['tuples'])} tuples returned")

        # 6. CreateStore
        print("6. CreateStore (POST /stores)")
        raw = await fga_client.execute_api_request(
            operation_name="CreateStore",
            method="POST",
            path="/stores",
            body={"name": "executor_test_store"},
        )
        body = raw.json()
        assert raw.status == 201, f"Expected 201, got {raw.status}"
        assert "id" in body
        new_store_id = body["id"]
        print(f"   created store: {new_store_id}")

        # 7. DeleteStore
        print("7. DeleteStore (DELETE /stores/{{store_id}})")
        raw = await fga_client.execute_api_request(
            operation_name="DeleteStore",
            method="DELETE",
            path="/stores/{store_id}",
            path_params={"store_id": new_store_id},
        )
        assert raw.status == 204, f"Expected 204, got {raw.status}"
        print(f"   deleted store: {new_store_id} (status 204)")

        # 8. Custom headers
        print("8. Custom headers (GET /stores/{{store_id}})")
        raw = await fga_client.execute_api_request(
            operation_name="GetStoreWithHeaders",
            method="GET",
            path="/stores/{store_id}",
            path_params={"store_id": store.id},
            headers={"X-Custom-Header": "test-value"},
        )
        assert raw.status == 200
        print(f"   custom headers accepted (status {raw.status})")

        # 9. StreamedListObjects
        print(
            "9. StreamedListObjects (POST /stores/{{store_id}}/streamed-list-objects)"
        )
        chunks = []
        async for chunk in fga_client.execute_streamed_api_request(
            operation_name="StreamedListObjects",
            method="POST",
            path="/stores/{store_id}/streamed-list-objects",
            path_params={"store_id": store.id},
            body={
                "type": "document",
                "relation": "viewer",
                "user": "user:anne",
                "authorization_model_id": auth_model_id,
            },
        ):
            chunks.append(chunk)
        assert len(chunks) >= 1, f"Expected at least 1 chunk, got {len(chunks)}"
        objects = [c["result"]["object"] for c in chunks if "result" in c]
        assert "document:roadmap" in objects, f"Expected document:roadmap in {objects}"
        print(f"   {len(chunks)} chunks, objects={objects}")

        # Cleanup
        print("\n=== Cleanup ===")
        await fga_client.delete_store()
        print(f"Deleted test store: {store.id}")

        print("\nAll examples completed successfully.\n")


asyncio.run(main())
