#####################################################################
# This files has been automatically generated from:
#   ../async/test_sdk_bypass_async.py
#
# DO NOT EDIT THIS FILE! Edit the async test case listed above,
# and regenerate the synchronous test cases with async2sync.py
#####################################################################
"""Test bypassing the SDK and accessing the API server directly."""

# This test case helps to differentiate between actual SDK failures
# and general failures due to an incorrect test environment setup.

import logging
import uuid
import warnings

from typing import Any, ContextManager

import pytest

from httpx_ws import connect_ws, WebSocketSession

from lmstudio import Client


@pytest.mark.lmstudio
def test_connect_and_predict_sync(caplog: Any) -> None:
    # Access the default API host directly
    api_host = Client.find_default_local_api_host()
    model_identifier = "hugging-quants/llama-3.2-1b-instruct"
    prompt = "Hello"

    caplog.set_level(logging.DEBUG)
    ws_cm: ContextManager[WebSocketSession] = connect_ws(f"ws://{api_host}/llm")

    with ws_cm as ws:
        # Authenticate
        client_identifier = str(uuid.uuid4())
        client_passkey = str(uuid.uuid4())
        auth_message = {
            "authVersion": 1,
            "clientIdentifier": client_identifier,
            "clientPasskey": client_passkey,
        }
        ws.send_json(auth_message)
        auth_result = ws.receive_json()
        if not auth_result["success"]:
            raise Exception(f"Authentication failed: {auth_result['error']}")

        # Send prediction request
        channel_id = 1
        creation_parameter = {
            "modelSpecifier": {
                "type": "query",
                "query": {"identifier": model_identifier},
            },
            "history": {
                "messages": [
                    {"role": "user", "content": [{"type": "text", "text": prompt}]}
                ]
            },
            "predictionConfigStack": {"layers": []},
        }
        create_message = {
            "type": "channelCreate",
            "endpoint": "predict",
            "channelId": channel_id,
            "creationParameter": creation_parameter,
        }
        ws.send_json(create_message)

        # Process prediction response
        fragments = []
        while True:
            message = ws.receive_json()

            match message:
                case {"type": "channelSend", "message": contents}:
                    match contents:
                        case {"type": "fragment", "fragment": {"content": fragment}}:
                            fragments.append(fragment)
                        case {"type": "fragment", "fragment": fragment}:
                            # Older LM Studio instance where message fragments were just strings
                            fragments.append(fragment)
                        case {"type": "success"}:
                            # We're done here
                            break
                case {"type": "channelError", "error": error}:
                    raise Exception(f"Prediction error: {error}")
                case {"type": "communicationWarning", "warning": warning}:
                    warnings.warn(f"Channel warning: {warning}")

    response = "".join(fragments)

    # The initial query from the LLM will change, but we expect it to be a question
    logging.info(f"LLM response: {response!r}")
    assert "?" in response
