"""Unit tests for content.publishing.youtube."""

from __future__ import annotations

from unittest.mock import MagicMock, patch

import pytest

from content.publishing.youtube import (
    YouTubeUploadResult,
    _daily_upload_count,
    _increment_daily_upload_count,
    _youtube_available,
    upload_episode,
)

# ── _youtube_available ────────────────────────────────────────────────────────


class TestYoutubeAvailable:
    def test_returns_bool(self):
        assert isinstance(_youtube_available(), bool)

    def test_false_when_library_missing(self):
        with patch("importlib.util.find_spec", return_value=None):
            assert _youtube_available() is False


# ── daily upload counter ──────────────────────────────────────────────────────


class TestDailyUploadCounter:
    def test_zero_when_no_file(self, tmp_path):
        counter_path = tmp_path / "counter.json"
        with patch(
            "content.publishing.youtube.settings",
            MagicMock(content_youtube_counter_file=str(counter_path)),
        ):
            assert _daily_upload_count() == 0

    def test_increments_correctly(self, tmp_path):
        counter_path = tmp_path / "counter.json"
        mock_settings = MagicMock(content_youtube_counter_file=str(counter_path))

        with patch("content.publishing.youtube.settings", mock_settings):
            assert _daily_upload_count() == 0
            _increment_daily_upload_count()
            assert _daily_upload_count() == 1
            _increment_daily_upload_count()
            assert _daily_upload_count() == 2

    def test_persists_across_calls(self, tmp_path):
        counter_path = tmp_path / "counter.json"
        mock_settings = MagicMock(content_youtube_counter_file=str(counter_path))

        with patch("content.publishing.youtube.settings", mock_settings):
            _increment_daily_upload_count()
            _increment_daily_upload_count()

        with patch("content.publishing.youtube.settings", mock_settings):
            assert _daily_upload_count() == 2


# ── upload_episode ────────────────────────────────────────────────────────────


class TestUploadEpisode:
    @pytest.mark.asyncio
    async def test_returns_failure_when_library_missing(self, tmp_path):
        video = tmp_path / "ep.mp4"
        video.write_bytes(b"fake")
        with patch("content.publishing.youtube._youtube_available", return_value=False):
            result = await upload_episode(str(video), "Title")
        assert result.success is False
        assert "google" in result.error.lower()

    @pytest.mark.asyncio
    async def test_returns_failure_when_video_missing(self, tmp_path):
        with patch("content.publishing.youtube._youtube_available", return_value=True):
            result = await upload_episode(str(tmp_path / "nonexistent.mp4"), "Title")
        assert result.success is False
        assert "not found" in result.error

    @pytest.mark.asyncio
    async def test_returns_failure_when_quota_reached(self, tmp_path):
        video = tmp_path / "ep.mp4"
        video.write_bytes(b"fake")
        with (
            patch("content.publishing.youtube._youtube_available", return_value=True),
            patch("content.publishing.youtube._daily_upload_count", return_value=6),
        ):
            result = await upload_episode(str(video), "Title")
        assert result.success is False
        assert "quota" in result.error.lower()

    @pytest.mark.asyncio
    async def test_successful_upload(self, tmp_path):
        video = tmp_path / "ep.mp4"
        video.write_bytes(b"fake video data")

        fake_upload_result = YouTubeUploadResult(
            success=True,
            video_id="abc123",
            video_url="https://www.youtube.com/watch?v=abc123",
        )

        with (
            patch("content.publishing.youtube._youtube_available", return_value=True),
            patch("content.publishing.youtube._daily_upload_count", return_value=0),
            patch(
                "asyncio.to_thread",
                return_value=fake_upload_result,
            ),
        ):
            result = await upload_episode(str(video), "My Episode Title")

        assert result.success is True
        assert result.video_id == "abc123"
        assert "abc123" in result.video_url

    @pytest.mark.asyncio
    async def test_title_truncated_to_100_chars(self, tmp_path):
        video = tmp_path / "ep.mp4"
        video.write_bytes(b"fake")
        long_title = "A" * 150

        captured_args = {}

        async def _capture_to_thread(fn, *args, **kwargs):
            captured_args["title"] = args[1]  # title is second positional arg
            return YouTubeUploadResult(success=True, video_id="x")

        with (
            patch("content.publishing.youtube._youtube_available", return_value=True),
            patch("content.publishing.youtube._daily_upload_count", return_value=0),
            patch("asyncio.to_thread", side_effect=_capture_to_thread),
        ):
            await upload_episode(str(video), long_title)

        assert len(captured_args["title"]) <= 100

    @pytest.mark.asyncio
    async def test_default_tags_is_empty_list(self, tmp_path):
        video = tmp_path / "ep.mp4"
        video.write_bytes(b"fake")
        captured_args = {}

        async def _capture(fn, *args, **kwargs):
            captured_args["tags"] = args[3]
            return YouTubeUploadResult(success=True, video_id="x")

        with (
            patch("content.publishing.youtube._youtube_available", return_value=True),
            patch("content.publishing.youtube._daily_upload_count", return_value=0),
            patch("asyncio.to_thread", side_effect=_capture),
        ):
            await upload_episode(str(video), "Title")

        assert captured_args["tags"] == []
