"""Unit tests for the file service."""

import json
from pathlib import Path
from unittest.mock import Mock

import pytest

from summary.core import file_service
from summary.core.file_service import (
    MediaInfo,
    extract_audio_from_media,
    get_media_info,
)

BASE_PATH = Path(__file__).parent.parent / "assets"

MEDIA_INFO_SAMPLE_VISIO = MediaInfo(
    path=BASE_PATH / "video-sample-visio.mp4",
    has_audio=True,
    has_video=True,
    audio_duration_seconds=5.34059,
    audio_codec_name="aac",
)


@pytest.mark.parametrize(
    "media_info",
    [
        MediaInfo(
            path=BASE_PATH / "audio-sample-android-chrome.webm",
            has_audio=True,
            has_video=False,
            audio_duration_seconds=2.2795,
            audio_codec_name="opus",
        ),
        MediaInfo(
            path=BASE_PATH / "audio-sample-android-firefox.ogg",
            has_audio=True,
            has_video=False,
            audio_duration_seconds=2.3025,
            audio_codec_name="opus",
        ),
        MediaInfo(
            path=BASE_PATH / "audio-sample-android.m4a",
            has_audio=True,
            has_video=False,
            audio_duration_seconds=1.38,
            audio_codec_name="aac",
        ),
        MediaInfo(
            path=BASE_PATH / "audio-sample-chromium.webm",
            has_audio=True,
            has_video=False,
            audio_duration_seconds=2.65,
            audio_codec_name="opus",
        ),
        MediaInfo(
            path=BASE_PATH / "audio-sample-firefox.ogg",
            has_audio=True,
            has_video=False,
            audio_duration_seconds=2.0865,
            audio_codec_name="opus",
        ),
        MediaInfo(
            path=BASE_PATH / "audio-sample-ios-browser.webm",
            has_audio=True,
            has_video=False,
            audio_duration_seconds=2.6229,
            audio_codec_name="opus",
        ),
        MediaInfo(
            path=BASE_PATH / "audio-sample-ios.m4a",
            has_audio=True,
            has_video=False,
            audio_duration_seconds=1.408,
            audio_codec_name="aac",
        ),
        MediaInfo(
            path=BASE_PATH / "audio-sample-mac-os-safari.webm",
            has_audio=True,
            has_video=False,
            audio_duration_seconds=2.3049,
            audio_codec_name="opus",
        ),
        MEDIA_INFO_SAMPLE_VISIO,
    ],
)
def test_validate_media_info_supports_all_used_file_formats(
    media_info: MediaInfo,
) -> None:
    """Validate media_info for different files that the service can handle."""
    res = get_media_info(media_info.path)
    assert res.has_audio == media_info.has_audio
    assert res.has_video == media_info.has_video
    assert res.audio_codec_name == media_info.audio_codec_name
    if res.has_audio:
        assert res.audio_duration_seconds == pytest.approx(
            media_info.audio_duration_seconds, 1e-3
        )
    else:
        assert res.audio_duration_seconds is None


def test_media_info_invalid_file() -> None:
    """Test that media_info returns correct values for invalid files."""
    assert get_media_info(Path(__file__)) == MediaInfo(
        path=Path(__file__),
        has_audio=False,
        has_video=False,
        audio_duration_seconds=None,
        audio_codec_name=None,
    )


def test_media_info_ignores_empty_stream_entry(monkeypatch: pytest.MonkeyPatch) -> None:
    """Test stream parsing when ffprobe returns an empty stream object."""
    ffprobe_payload = {
        "programs": [],
        "stream_groups": [],
        "streams": [
            {"codec_name": "vorbis", "codec_type": "audio"},
            {},
        ],
    }

    run_mock = Mock(
        return_value=Mock(stdout=json.dumps(ffprobe_payload), stderr="", returncode=0)
    )
    monkeypatch.setattr(file_service.subprocess, "run", run_mock)
    monkeypatch.setattr(
        file_service, "get_media_duration_seconds", Mock(return_value=2.5)
    )

    media_info = get_media_info(BASE_PATH / "audio-sample-android-firefox.ogg")

    assert media_info.has_audio is True
    assert media_info.has_video is False
    assert media_info.has_bad_stream is True
    assert media_info.audio_codec_name == "vorbis"
    assert media_info.audio_duration_seconds == 2.5


def test_extract_audio_from_video():
    """Test that extract_audio_from_video can extract audio from a video file."""
    path = extract_audio_from_media(MEDIA_INFO_SAMPLE_VISIO)
    # A bit of cleanup logic since this is not a generator
    try:
        assert path.name.endswith(".m4a")
    finally:
        path.unlink(missing_ok=True)
