"""Unit tests for image helpers."""

import base64
from pathlib import Path

import pytest

from dotpromptz.blocks import is_block_line
from dotpromptz.image import (
    infer_image_mime,
    normalize_media_messages,
    resolve_image_ref,
    resolve_image_value,
)
from dotpromptz.typing import MediaContent, MediaPart, Message, Role


def test_resolve_image_value_returns_first_non_empty_line() -> None:
    lines = [':::image', '', '   ', 'https://example.com/cat.png', 'next']
    result = resolve_image_value(lines, 0, is_block_line=is_block_line)
    assert result is not None
    value, idx = result
    assert value == 'https://example.com/cat.png'
    assert idx == 3


def test_resolve_image_value_returns_none_when_next_block_before_value() -> None:
    lines = [':::image', '', ':::user', 'hello']
    result = resolve_image_value(lines, 0, is_block_line=is_block_line)
    assert result is None


def test_resolve_image_value_returns_none_on_eof_without_value() -> None:
    lines = [':::image', '', '   ']
    result = resolve_image_value(lines, 0, is_block_line=is_block_line)
    assert result is None


@pytest.mark.parametrize(
    ('value', 'expected'),
    [
        ('image.png', 'image/png'),
        ('image.jpg', 'image/jpeg'),
        ('image.jpeg', 'image/jpeg'),
        ('image.webp', 'image/webp'),
        ('image.gif', 'image/gif'),
        ('https://example.com/x/a.png?token=1', 'image/png'),
    ],
)
def test_infer_image_mime_with_known_suffixes(value: str, expected: str) -> None:
    mime_type, used_default = infer_image_mime(value)
    assert mime_type == expected
    assert used_default is False


def test_infer_image_mime_falls_back_to_png() -> None:
    mime_type, used_default = infer_image_mime('https://example.com/resource')
    assert mime_type == 'image/png'
    assert used_default is True


_RED_DOT_PNG_B64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4////fwAJ+wP9KobjigAAAABJRU5ErkJggg=='


def _write_png(path: Path) -> Path:
    """Write a tiny valid PNG file for local image-path tests."""
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_bytes(base64.b64decode(_RED_DOT_PNG_B64))
    return path


def test_resolve_image_ref_for_remote_url() -> None:
    ref = resolve_image_ref('https://example.com/cat.png')
    assert ref.kind == 'remote_url'
    assert ref.url == 'https://example.com/cat.png'
    assert ref.mime_type == 'image/png'


def test_resolve_image_ref_reads_remote_bytes_when_enabled(monkeypatch: pytest.MonkeyPatch) -> None:
    expected = b'remote-png-bytes'

    def _fake_read(url: str, *, timeout_seconds: float) -> bytes:
        assert url == 'https://example.com/cat.png'
        assert timeout_seconds == 2.5
        return expected

    monkeypatch.setattr('dotpromptz.image._read_remote_image_bytes', _fake_read)
    ref = resolve_image_ref(
        'https://example.com/cat.png',
        read_bytes=True,
        read_remote_bytes=True,
        remote_timeout_seconds=2.5,
    )
    assert ref.kind == 'remote_url'
    assert ref.data == expected


def test_resolve_image_ref_rejects_data_uri() -> None:
    with pytest.raises(ValueError, match='data: image URLs are not supported'):
        resolve_image_ref('data:image/png;base64,abc123')


def test_resolve_image_ref_resolves_relative_path_from_prompt_dir(tmp_path: Path) -> None:
    prompt_file = tmp_path / 'prompts' / 'demo.prompt'
    prompt_file.parent.mkdir(parents=True, exist_ok=True)
    prompt_file.write_text('---\nversion: 1\n---\n', encoding='utf-8')
    image_path = _write_png(prompt_file.parent / 'assets' / 'cat.png')

    ref = resolve_image_ref('assets/cat.png', prompt_file_path=prompt_file, read_bytes=True)
    assert ref.kind == 'local_file'
    assert ref.file_path == image_path.resolve()
    assert ref.mime_type == 'image/png'
    assert ref.data == image_path.read_bytes()


def test_resolve_image_ref_supports_absolute_path(tmp_path: Path) -> None:
    image_path = _write_png(tmp_path / 'abs' / 'red.png')
    ref = resolve_image_ref(str(image_path), read_bytes=True)
    assert ref.kind == 'local_file'
    assert ref.file_path == image_path.resolve()
    assert ref.data == image_path.read_bytes()


def test_normalize_media_messages_resolves_local_path(tmp_path: Path) -> None:
    prompt_file = tmp_path / 'sample.prompt'
    prompt_file.write_text('---\nversion: 1\n---\n', encoding='utf-8')
    image_path = _write_png(tmp_path / 'images' / 'foo.png')
    messages = [
        Message(
            role=Role.USER,
            content=[MediaPart(media=MediaContent(url='images/foo.png', content_type='image/png'))],
        )
    ]

    normalized = normalize_media_messages(messages, prompt_file_path=prompt_file)
    media = normalized[0].content[0].media
    assert media.url == str(image_path.resolve())
    assert media.content_type == 'image/png'


def test_normalize_media_messages_rejects_data_uri() -> None:
    messages = [
        Message(
            role=Role.USER,
            content=[MediaPart(media=MediaContent(url='data:image/png;base64,abc', content_type='image/png'))],
        )
    ]
    with pytest.raises(ValueError, match='data: image URLs are not supported'):
        normalize_media_messages(messages)
