#!/usr/bin/env python3
"""
Tests for YouTube History Fetcher

Black Box Tests: Test external behavior
White Box Tests: Test internal paths and edge cases
"""

import os
import sys
import json
import pytest
from pathlib import Path
from unittest.mock import Mock, patch, MagicMock
from datetime import datetime, timedelta
import tempfile

# Add genesis-system to path
sys.path.insert(0, '/mnt/e/genesis-system')

from core.youtube.history_fetcher import (
    YouTubeHistoryFetcher,
    VideoInfo,
    PostgreSQLDeduplicator,
    DATA_DIR
)


class TestVideoInfoBlackBox:
    """Black box tests for VideoInfo dataclass."""

    def test_video_info_creation(self):
        """Test creating a VideoInfo object."""
        video = VideoInfo(
            video_id="abc123def45",
            title="Test Video",
            channel="Test Channel",
            channel_id="UC123",
            published_at="2026-01-01T00:00:00Z"
        )
        assert video.video_id == "abc123def45"
        assert video.title == "Test Video"
        assert video.source == "api"

    def test_video_info_auto_discovered_at(self):
        """Test that discovered_at is auto-populated."""
        video = VideoInfo(
            video_id="abc123def45",
            title="Test",
            channel="Channel",
            channel_id="UC123",
            published_at="2026-01-01T00:00:00Z"
        )
        assert video.discovered_at is not None
        assert "T" in video.discovered_at

    def test_video_info_custom_source(self):
        """Test custom source field."""
        video = VideoInfo(
            video_id="abc123def45",
            title="Test",
            channel="Channel",
            channel_id="UC123",
            published_at="2026-01-01T00:00:00Z",
            source="takeout"
        )
        assert video.source == "takeout"


class TestPostgreSQLDeduplicatorBlackBox:
    """Black box tests for PostgreSQL deduplicator."""

    def test_deduplicator_creation(self):
        """Test deduplicator can be created."""
        with patch('psycopg2.connect') as mock_connect:
            mock_connect.return_value = MagicMock()
            dedup = PostgreSQLDeduplicator()
            assert dedup is not None

    def test_deduplicator_no_psycopg2(self):
        """Test graceful handling when psycopg2 not available."""
        with patch.dict('sys.modules', {'psycopg2': None}):
            # This should not crash
            dedup = PostgreSQLDeduplicator()
            result = dedup.get_processed_video_ids()
            assert result == set()

    def test_get_processed_ids_returns_set(self):
        """Test that get_processed_video_ids returns a set."""
        with patch('psycopg2.connect') as mock_connect:
            mock_conn = MagicMock()
            mock_cursor = MagicMock()
            mock_cursor.fetchall.return_value = [('vid1',), ('vid2',)]
            mock_conn.cursor.return_value.__enter__ = Mock(return_value=mock_cursor)
            mock_conn.cursor.return_value.__exit__ = Mock(return_value=False)
            mock_connect.return_value = mock_conn

            dedup = PostgreSQLDeduplicator()
            result = dedup.get_processed_video_ids()

            assert isinstance(result, set)
            assert 'vid1' in result
            assert 'vid2' in result


class TestYouTubeHistoryFetcherBlackBox:
    """Black box tests for YouTube History Fetcher."""

    def test_fetcher_creation_no_credentials(self):
        """Test fetcher can be created without credentials."""
        with patch('core.youtube.history_fetcher.YouTubeHistoryFetcher._init_api'):
            fetcher = YouTubeHistoryFetcher()
            assert fetcher is not None

    def test_fetch_liked_returns_list(self):
        """Test fetch_liked_videos returns a list."""
        with patch('core.youtube.history_fetcher.YouTubeHistoryFetcher._init_api'):
            fetcher = YouTubeHistoryFetcher()
            fetcher.youtube = None
            result = fetcher.fetch_liked_videos()
            assert isinstance(result, list)
            assert len(result) == 0  # No API, empty result


class TestYouTubeHistoryFetcherWhiteBox:
    """White box tests for internal logic."""

    def test_parse_takeout_json(self):
        """Test parsing Google Takeout JSON format."""
        with patch('core.youtube.history_fetcher.YouTubeHistoryFetcher._init_api'):
            fetcher = YouTubeHistoryFetcher()

            # Create temp JSON file
            takeout_data = [
                {
                    "titleUrl": "https://www.youtube.com/watch?v=abc123def45",
                    "title": "Test Video",
                    "subtitles": [{"name": "Test Channel"}],
                    "time": "2026-01-01T00:00:00Z"
                },
                {
                    "titleUrl": "https://www.youtube.com/watch?v=xyz789ghi01",
                    "title": "Another Video",
                    "subtitles": [{"name": "Another Channel"}],
                    "time": "2026-01-02T00:00:00Z"
                }
            ]

            with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
                json.dump(takeout_data, f)
                temp_path = Path(f.name)

            try:
                videos = fetcher.parse_takeout_history(temp_path)
                assert len(videos) == 2
                assert videos[0].video_id == "abc123def45"
                assert videos[0].title == "Test Video"
                assert videos[0].source == "takeout"
            finally:
                temp_path.unlink()

    def test_parse_takeout_html(self):
        """Test parsing Google Takeout HTML format."""
        with patch('core.youtube.history_fetcher.YouTubeHistoryFetcher._init_api'):
            fetcher = YouTubeHistoryFetcher()

            html_content = '''
            <html>
            <body>
            <a href="https://www.youtube.com/watch?v=abc123def45">Test Video Title</a>
            <a href="https://www.youtube.com/watch?v=xyz789ghi01">Another Video</a>
            </body>
            </html>
            '''

            with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) as f:
                f.write(html_content)
                temp_path = Path(f.name)

            try:
                videos = fetcher.parse_takeout_history(temp_path)
                assert len(videos) == 2
                assert videos[0].video_id == "abc123def45"
                assert videos[0].title == "Test Video Title"
            finally:
                temp_path.unlink()

    def test_parse_takeout_missing_file(self):
        """Test handling of missing takeout file."""
        with patch('core.youtube.history_fetcher.YouTubeHistoryFetcher._init_api'):
            fetcher = YouTubeHistoryFetcher()
            result = fetcher.parse_takeout_history(Path("/nonexistent/file.json"))
            assert result == []

    def test_deduplication_logic(self):
        """Test that deduplication removes processed videos."""
        with patch('core.youtube.history_fetcher.YouTubeHistoryFetcher._init_api'):
            fetcher = YouTubeHistoryFetcher()

            # Mock the deduplicator
            fetcher.deduplicator = MagicMock()
            fetcher.deduplicator.get_processed_video_ids.return_value = {'vid1', 'vid3'}

            # Create test videos
            test_videos = [
                VideoInfo(video_id='vid1', title='V1', channel='C', channel_id='UC1', published_at='2026-01-01'),
                VideoInfo(video_id='vid2', title='V2', channel='C', channel_id='UC1', published_at='2026-01-01'),
                VideoInfo(video_id='vid3', title='V3', channel='C', channel_id='UC1', published_at='2026-01-01'),
            ]

            # Simulate fetch_all logic
            all_videos = {v.video_id: v for v in test_videos}
            processed_ids = fetcher.deduplicator.get_processed_video_ids()
            filtered = [v for v in all_videos.values() if v.video_id not in processed_ids]

            assert len(filtered) == 1
            assert filtered[0].video_id == 'vid2'

    def test_save_results(self):
        """Test saving results to JSON."""
        with patch('core.youtube.history_fetcher.YouTubeHistoryFetcher._init_api'):
            fetcher = YouTubeHistoryFetcher()

            videos = [
                VideoInfo(video_id='test1', title='Test', channel='C', channel_id='UC1', published_at='2026-01-01'),
            ]

            with tempfile.TemporaryDirectory() as tmpdir:
                output_path = Path(tmpdir) / "test_output.json"
                result_path = fetcher.save_results(videos, output_path)

                assert result_path.exists()
                with open(result_path) as f:
                    data = json.load(f)
                assert data['count'] == 1
                assert data['videos'][0]['video_id'] == 'test1'


class TestYouTubeHistoryFetcherIntegration:
    """Integration tests (require credentials)."""

    @pytest.mark.skipif(
        not Path("/mnt/e/genesis-system/config/youtube_token.json").exists(),
        reason="No OAuth token configured"
    )
    def test_fetch_liked_with_real_api(self):
        """Test fetching liked videos with real API."""
        fetcher = YouTubeHistoryFetcher()
        if fetcher.youtube:
            videos = fetcher.fetch_liked_videos(max_results=5)
            assert isinstance(videos, list)
            fetcher.close()

    @pytest.mark.skipif(
        not Path("/mnt/e/genesis-system/config/youtube_token.json").exists(),
        reason="No OAuth token configured"
    )
    def test_fetch_subscriptions_with_real_api(self):
        """Test fetching subscription uploads with real API."""
        fetcher = YouTubeHistoryFetcher()
        if fetcher.youtube:
            videos = fetcher.fetch_subscription_uploads(max_channels=3, days_back=7)
            assert isinstance(videos, list)
            fetcher.close()


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
