#!/usr/bin/env python3
"""
Tests for YouTube OAuth module

Black Box Tests: Test external behavior without implementation knowledge
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

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

from core.youtube.youtube_oauth import YouTubeOAuth, SCOPES, TOKEN_PATH, CLIENT_SECRET_PATH


class TestYouTubeOAuthBlackBox:
    """Black box tests - test from outside without implementation knowledge."""

    def test_oauth_instance_creation(self):
        """Test that OAuth instance can be created."""
        oauth = YouTubeOAuth()
        assert oauth is not None

    def test_scopes_defined(self):
        """Test that required scopes are defined."""
        assert 'https://www.googleapis.com/auth/youtube.readonly' in SCOPES
        assert len(SCOPES) >= 1

    def test_paths_defined(self):
        """Test that file paths are properly defined."""
        assert TOKEN_PATH.suffix == '.json'
        assert CLIENT_SECRET_PATH.suffix == '.json'
        assert 'genesis-system' in str(TOKEN_PATH)

    def test_credentials_none_without_token(self):
        """Test that credentials are None when no token exists."""
        with patch.object(Path, 'exists', return_value=False):
            oauth = YouTubeOAuth()
            # Should not crash, credentials may be None or loaded from elsewhere
            assert oauth is not None

    def test_get_watch_history_returns_list(self):
        """Test that get_watch_history returns a list."""
        oauth = YouTubeOAuth()
        # Without valid credentials, should return empty list
        with patch.object(oauth, 'get_credentials', return_value=None):
            result = oauth.get_watch_history()
            assert isinstance(result, list)


class TestYouTubeOAuthWhiteBox:
    """White box tests - test internal paths and edge cases."""

    def test_load_existing_token_no_file(self):
        """Test loading token when file doesn't exist."""
        with patch.object(Path, 'exists', return_value=False):
            oauth = YouTubeOAuth()
            result = oauth._load_existing_token()
            assert result == False

    def test_load_existing_token_expired(self):
        """Test loading token when token is expired."""
        expired_token = {
            'token': 'test_token',
            'refresh_token': 'test_refresh',
            'expiry': (datetime.now() - timedelta(hours=1)).isoformat()
        }

        with patch.object(Path, 'exists', return_value=True):
            with patch('builtins.open', create=True) as mock_open:
                mock_open.return_value.__enter__.return_value.read.return_value = json.dumps(expired_token)
                with patch('json.load', return_value=expired_token):
                    oauth = YouTubeOAuth()
                    result = oauth._load_existing_token()
                    assert result == False

    def test_load_existing_token_valid(self):
        """Test loading token when token is valid."""
        valid_token = {
            'token': 'test_token',
            'refresh_token': 'test_refresh',
            'token_uri': 'https://oauth2.googleapis.com/token',
            'client_id': 'test_client_id',
            'client_secret': 'test_secret',
            'scopes': SCOPES,
            'expiry': (datetime.now() + timedelta(hours=1)).isoformat()
        }

        mock_file = MagicMock()
        mock_file.__enter__ = MagicMock(return_value=mock_file)
        mock_file.__exit__ = MagicMock(return_value=False)

        with patch.object(Path, 'exists', return_value=True):
            with patch('builtins.open', return_value=mock_file):
                with patch('json.load', return_value=valid_token):
                    oauth = YouTubeOAuth()
                    result = oauth._load_existing_token()
                    assert result == True
                    assert oauth.credentials == valid_token

    def test_setup_oauth_no_client_secret(self):
        """Test OAuth setup fails gracefully without client secret."""
        with patch.object(Path, 'exists', return_value=False):
            oauth = YouTubeOAuth()
            # Mock the import to succeed
            with patch.dict('sys.modules', {
                'google_auth_oauthlib.flow': MagicMock(),
                'google.auth.transport.requests': MagicMock(),
                'google.oauth2.credentials': MagicMock()
            }):
                result = oauth.setup_oauth()
                assert result == False

    def test_refresh_token_no_existing_token(self):
        """Test refresh fails when no token exists."""
        with patch.object(Path, 'exists', return_value=False):
            oauth = YouTubeOAuth()
            with patch.dict('sys.modules', {
                'google.oauth2.credentials': MagicMock(),
                'google.auth.transport.requests': MagicMock()
            }):
                result = oauth.refresh_token()
                assert result == False

    def test_get_credentials_no_token(self):
        """Test get_credentials returns None without token."""
        with patch.object(Path, 'exists', return_value=False):
            oauth = YouTubeOAuth()
            oauth.credentials = None
            with patch.dict('sys.modules', {'google.oauth2.credentials': MagicMock()}):
                result = oauth.get_credentials()
                assert result is None


class TestYouTubeOAuthIntegration:
    """Integration tests - require actual credentials (skipped in CI)."""

    @pytest.mark.skipif(
        not TOKEN_PATH.exists(),
        reason="No OAuth token configured"
    )
    def test_api_access_with_real_token(self):
        """Test API access with real credentials."""
        oauth = YouTubeOAuth()
        if oauth.credentials:
            result = oauth.test_api_access()
            assert result == True

    @pytest.mark.skipif(
        not TOKEN_PATH.exists(),
        reason="No OAuth token configured"
    )
    def test_watch_history_with_real_token(self):
        """Test watch history fetch with real credentials."""
        oauth = YouTubeOAuth()
        if oauth.credentials:
            videos = oauth.get_watch_history(max_results=5)
            assert isinstance(videos, list)


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