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

Consolidated into 2 mega-tests (1 API call each) that cover:
- Full Dotprompt render → generate pipeline with multi-turn, JSON Schema object, SCHEMA, structured JSON
- Vision (image input) with MediaPart
"""

import json
import logging

import jsonschema
import pytest

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

logger = logging.getLogger(__name__)

pytestmark = pytest.mark.integration

MODEL = 'gemini-3.1-flash-image-preview'
_PYTHON_PNG_URL = 'https://raw.githubusercontent.com/github/explore/main/topics/python/python.png'


# ---------------------------------------------------------------------------
# Mega Test 1 – Full pipeline: render → multi-turn → JSON Schema object → SCHEMA → structured JSON → metadata
# ---------------------------------------------------------------------------

_MEGA_PIPELINE_PROMPT = f"""\
---
version: 2
config:
  model: {MODEL}
  temperature: 1
output:
  format: json
  schema:
    type: object
    properties:
      name:
        type: string
      age:
        type: integer
      favorite_color:
        type: string
    required:
      - name
      - age
      - favorite_color
    additionalProperties: false
---
{{{{ 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, google_adapter) -> None:
    """Mega test covering: Dotprompt render, multi-turn (4 messages), JSON Schema object,
    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,
        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'

    # JSON Schema object was preserved in output config
    assert rendered.output is not None
    assert rendered.output.format == 'json'
    assert rendered.output.schema_value is not None
    assert 'properties' in rendered.output.schema_value
    assert 'name' in rendered.output.schema_value['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 google_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_value)

    # 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 – Vision (image input) with metadata
# ---------------------------------------------------------------------------


@pytest.mark.asyncio
async def test_mega_vision_image_input(google_adapter) -> None:
    """Mega test covering: image URL input, content_type handling,
    response text verification, and usage metadata.
    """
    rendered = RenderedPrompt(
        config={'model': MODEL, 'temperature': 1, '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=_PYTHON_PNG_URL,
                            contentType='image/png',
                        ),
                    ),
                    TextPart(
                        text='What programming language logo is shown in this image? Answer with just the language name.'
                    ),
                ],
            ),
        ],
    )

    response = await google_adapter.generate(rendered)

    # Vision response verification
    assert response.text is not None
    assert len(response.text.strip()) > 0
    assert 'python' 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)


@pytest.mark.asyncio
async def test_image_generate_google(google_image_adapter) -> None:
    """Generate an image with Gemini image model and validate PNG bytes."""
    rendered = RenderedPrompt(
        config={'model': MODEL, 'resolution': '1K', 'aspect_ratio': '1:1', 'transparent': True},
        output=PromptOutputConfig(format='image', file_name='image'),
        messages=[
            Message(role=Role.USER, content=[TextPart(text='A minimal flat icon of a blue whale on white background')]),
        ],
    )

    response = await google_image_adapter.generate(rendered)

    assert response.images is not None
    assert len(response.images) > 0
    first = response.images[0]
    assert first.mime_type == 'image/png'
    assert first.data.startswith(b'\x89PNG\r\n\x1a\n')
    logger.info('[e2e] google image generate bytes=%d', len(first.data))


@pytest.mark.asyncio
async def test_image_edit_google(google_image_adapter) -> None:
    """Edit an input image with Gemini image model and validate PNG bytes."""
    rendered = RenderedPrompt(
        config={'model': MODEL, 'resolution': '1K', 'aspect_ratio': '1:1'},
        output=PromptOutputConfig(format='image', file_name='image'),
        messages=[
            Message(
                role=Role.USER,
                content=[
                    MediaPart(media=MediaContent(url=_PYTHON_PNG_URL, contentType='image/png')),
                    TextPart(text='Keep the shape and change the color to green.'),
                ],
            ),
        ],
    )

    response = await google_image_adapter.generate(rendered)

    assert response.images is not None
    assert len(response.images) > 0
    first = response.images[0]
    assert first.mime_type == 'image/png'
    assert first.data.startswith(b'\x89PNG\r\n\x1a\n')
    logger.info('[e2e] google image edit bytes=%d', len(first.data))
