"""End-to-end integration tests – Dotprompt render → Anthropic adapter generate.

Consolidated into 3 mega-tests (1 API call each) that cover:
- Full Dotprompt render → generate pipeline with multi-turn, picoschema, @schema, structured JSON
- Tool calling with tool_defs and finish_reason verification
- Vision (image input) with MediaPart
"""

import json
import logging

import jsonschema
import pytest

from dotpromptz.typing import (
    DataArgument,
    MediaContent,
    MediaPart,
    Message,
    PromptOutputConfig,
    RenderedPrompt,
    Role,
    TextPart,
    ToolDefinition,
)

logger = logging.getLogger(__name__)

pytestmark = pytest.mark.integration

MODEL = 'claude-haiku-4-5-20251001'


# ---------------------------------------------------------------------------
# Mega Test 1 – Full pipeline: render → multi-turn → picoschema → @schema → structured JSON → metadata
# ---------------------------------------------------------------------------

_MEGA_PIPELINE_PROMPT = f"""\
---
model: {MODEL}
config:
  temperature: 0
output:
  format: json
  schema:
    name: string, the person's full name
    age: integer, age in years
    favorite_color: string, their favorite color
---
{{{{role "system"}}}}
You are a data extraction assistant.
Output valid JSON conforming to this schema: {{{{SCHEMA}}}}
{{{{role "user"}}}}
I will describe a person for you to extract.
{{{{role "model"}}}}
Understood. Please describe the person.
{{{{role "user"}}}}
Extract info: {{{{person_description}}}}
"""


@pytest.mark.asyncio
async def test_mega_pipeline_render_multiturn_json(dotprompt_instance, anthropic_adapter) -> None:
    """Mega test covering: Dotprompt render, multi-turn (4 messages), picoschema,
    @schema auto-variable injection, structured JSON output, and response metadata.

    Single API call exercises the full Dotprompt → adapter pipeline.
    """
    rendered = dotprompt_instance.render(
        _MEGA_PIPELINE_PROMPT,
        data=DataArgument(input={'person_description': 'Alice is 30 years old and her favorite color is blue.'}),
    )

    # --- Verify rendering (pre-API) ---
    # Multi-turn: system + user + model + user = 4 messages
    assert len(rendered.messages) == 4, f'Expected 4 messages, got {len(rendered.messages)}'
    assert rendered.messages[0].role == Role.SYSTEM
    assert rendered.messages[1].role == Role.USER
    assert rendered.messages[2].role == Role.MODEL
    assert rendered.messages[3].role == Role.USER

    # @schema was injected into system message
    system_text = ''.join(p.text for p in rendered.messages[0].content if hasattr(p, 'text'))
    assert '"name"' in system_text, '@schema should contain "name" field'
    assert '"age"' in system_text, '@schema should contain "age" field'
    assert '"favorite_color"' in system_text, '@schema should contain "favorite_color" field'

    # Picoschema was converted to JSON schema in output config
    assert rendered.output is not None
    assert rendered.output.format == 'json'
    assert rendered.output.schema is not None
    assert 'properties' in rendered.output.schema
    assert 'name' in rendered.output.schema['properties']

    # User variable was substituted
    last_msg_text = ''.join(p.text for p in rendered.messages[3].content if hasattr(p, 'text'))
    assert 'Alice' in last_msg_text

    # --- Call the real API (single API call) ---
    response = await anthropic_adapter.generate(rendered)

    # --- Verify response ---
    assert response.text is not None
    data = json.loads(response.text)

    # Validate against the resolved schema
    jsonschema.validate(instance=data, schema=rendered.output.schema)

    # Verify concrete values
    assert data['name'] == 'Alice'
    assert isinstance(data['age'], int)
    assert data['age'] == 30
    assert data['favorite_color'] == 'blue'

    # Response metadata
    assert response.model is not None
    assert response.usage is not None
    assert response.usage.prompt_tokens > 0
    assert response.usage.completion_tokens > 0
    logger.info('[e2e] mega pipeline: data=%s model=%s', data, response.model)


# ---------------------------------------------------------------------------
# Mega Test 2 – Tool calling with finish_reason
# ---------------------------------------------------------------------------


@pytest.mark.asyncio
async def test_mega_tool_calling(anthropic_adapter) -> None:
    """Mega test covering: tool_defs with input_schema, tool call name/args extraction,
    finish_reason='tool_use', and response metadata.
    """
    rendered = RenderedPrompt(
        config={'model': MODEL, 'temperature': 0},
        messages=[
            Message(
                role=Role.SYSTEM,
                content=[TextPart(text='You are a helpful assistant. Use the provided tools when appropriate.')],
            ),
            Message(
                role=Role.USER,
                content=[TextPart(text='What is the weather in Tokyo right now?')],
            ),
        ],
        tool_defs=[
            ToolDefinition(
                name='get_weather',
                description='Get the current weather for a city.',
                input_schema={
                    'type': 'object',
                    'properties': {
                        'city': {'type': 'string', 'description': 'The city name'},
                    },
                    'required': ['city'],
                },
            ),
        ],
    )

    response = await anthropic_adapter.generate(rendered)

    # Tool call verification
    assert len(response.tool_calls) > 0
    tc = response.tool_calls[0]
    assert tc.name == 'get_weather'
    assert 'tokyo' in tc.arguments.get('city', '').lower()

    # Anthropic-specific finish_reason
    assert response.finish_reason == 'tool_use'

    # Response metadata
    assert response.model is not None
    assert response.usage is not None
    assert response.usage.prompt_tokens > 0
    assert response.usage.completion_tokens > 0
    logger.info('[e2e] mega tool: %s(%s) finish=%s', tc.name, tc.arguments, response.finish_reason)


# ---------------------------------------------------------------------------
# Mega Test 3 – Vision (image input) with metadata
# ---------------------------------------------------------------------------

# 100x100 solid-red PNG (334 bytes) as base64.
_RED_PNG_B64 = 'iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAABFUlEQVR4nO3OUQkAIABEsetfWiv4Nx4IC7Cd7XvkByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIX4Q4gchfhDiByF+EOIHIReeLesrH9s1agAAAABJRU5ErkJggg=='


@pytest.mark.asyncio
async def test_mega_vision_image_input(anthropic_adapter) -> None:
    """Mega test covering: MediaPart with base64 image, content_type handling,
    response text verification, and usage metadata.
    """
    rendered = RenderedPrompt(
        config={'model': MODEL, 'temperature': 0, 'max_tokens': 60},
        messages=[
            Message(
                role=Role.SYSTEM,
                content=[TextPart(text='You are a concise assistant. Describe images in one short sentence.')],
            ),
            Message(
                role=Role.USER,
                content=[
                    MediaPart(
                        media=MediaContent(
                            url=f'data:image/png;base64,{_RED_PNG_B64}',
                            content_type='image/png',
                        ),
                    ),
                    TextPart(text='What color is this image? Answer with just the color name.'),
                ],
            ),
        ],
    )

    response = await anthropic_adapter.generate(rendered)

    # Vision response verification
    assert response.text is not None
    assert len(response.text.strip()) > 0
    assert 'red' in response.text.lower()

    # Response metadata
    assert response.model is not None
    assert response.usage is not None
    assert response.usage.prompt_tokens > 0
    assert response.usage.completion_tokens > 0
    assert response.finish_reason is not None
    logger.info('[e2e] mega vision: text=%r model=%s', response.text, response.model)
