"""Unit tests for page controller.

This module tests the FastAPI page controller that serves HTML templates
for various application pages.

Coverage Target: 85%+
"""

from pathlib import Path
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from fastapi import Request


@pytest.fixture
def mock_request():
    """Create a mock FastAPI request."""
    request = MagicMock(spec=Request)
    request.url = MagicMock()
    request.url.path = "/"
    request.headers = {}
    return request


class TestRootEndpoint:
    """Test the root / endpoint."""
    
    @pytest.mark.asyncio
    async def test_root_endpoint_calls_render_template(self, mock_request):
        """Test root endpoint calls render_template."""
        from src.server.controllers.page_controller import root
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            result = await root(mock_request)
            
            mock_render.assert_called_once()
            call_args = mock_render.call_args[0]
            assert call_args[0] == "index.html"
    
    @pytest.mark.asyncio
    async def test_root_endpoint_passes_correct_title(self, mock_request):
        """Test root endpoint passes correct title."""
        from src.server.controllers.page_controller import root
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await root(mock_request)
            
            call_kwargs = mock_render.call_args[1]
            assert call_kwargs["title"] == "Aniworld Download Manager"


class TestSetupEndpoint:
    """Test the /setup endpoint."""
    
    @pytest.mark.asyncio
    async def test_setup_endpoint_renders_setup_html(self, mock_request):
        """Test setup endpoint renders setup.html template."""
        from src.server.controllers.page_controller import setup_page
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await setup_page(mock_request)
            
            call_args = mock_render.call_args[0]
            assert call_args[0] == "setup.html"
    
    @pytest.mark.asyncio
    async def test_setup_endpoint_title(self, mock_request):
        """Test setup endpoint passes correct title."""
        from src.server.controllers.page_controller import setup_page
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await setup_page(mock_request)
            
            call_kwargs = mock_render.call_args[1]
            assert call_kwargs["title"] == "Setup - Aniworld"


class TestLoginEndpoint:
    """Test the /login endpoint."""
    
    @pytest.mark.asyncio
    async def test_login_endpoint_renders_login_html(self, mock_request):
        """Test login endpoint renders login.html template."""
        from src.server.controllers.page_controller import login_page
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await login_page(mock_request)
            
            call_args = mock_render.call_args[0]
            assert call_args[0] == "login.html"
    
    @pytest.mark.asyncio
    async def test_login_endpoint_title(self, mock_request):
        """Test login endpoint passes correct title."""
        from src.server.controllers.page_controller import login_page
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await login_page(mock_request)
            
            call_kwargs = mock_render.call_args[1]
            assert call_kwargs["title"] == "Login - Aniworld"


class TestQueueEndpoint:
    """Test the /queue endpoint."""
    
    @pytest.mark.asyncio
    async def test_queue_endpoint_renders_queue_html(self, mock_request):
        """Test queue endpoint renders queue.html template."""
        from src.server.controllers.page_controller import queue_page
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await queue_page(mock_request)
            
            call_args = mock_render.call_args[0]
            assert call_args[0] == "queue.html"
    
    @pytest.mark.asyncio
    async def test_queue_endpoint_title(self, mock_request):
        """Test queue endpoint passes correct title."""
        from src.server.controllers.page_controller import queue_page
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await queue_page(mock_request)
            
            call_kwargs = mock_render.call_args[1]
            assert call_kwargs["title"] == "Download Queue - Aniworld"


class TestLoadingEndpoint:
    """Test the /loading endpoint."""
    
    @pytest.mark.asyncio
    async def test_loading_endpoint_renders_loading_html(self, mock_request):
        """Test loading endpoint renders loading.html template."""
        from src.server.controllers.page_controller import loading_page
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await loading_page(mock_request)
            
            call_args = mock_render.call_args[0]
            assert call_args[0] == "loading.html"
    
    @pytest.mark.asyncio
    async def test_loading_endpoint_title(self, mock_request):
        """Test loading endpoint passes correct title."""
        from src.server.controllers.page_controller import loading_page
        
        with patch('src.server.controllers.page_controller.render_template') as mock_render:
            mock_render.return_value = "<!DOCTYPE html><html></html>"
            
            await loading_page(mock_request)
            
            call_kwargs = mock_render.call_args[1]
            assert call_kwargs["title"] == "Initializing - Aniworld"


class TestTemplateHelpers:
    """Test template helper functions."""
    
    def test_get_base_context(self):
        """Test getting base context."""
        from src.server.utils.template_helpers import get_base_context
        
        mock_request = MagicMock(spec=Request)
        context = get_base_context(mock_request, "Test Title")
        
        assert context["request"] == mock_request
        assert context["title"] == "Test Title"
        assert context["app_name"] == "Aniworld Download Manager"
        assert context["version"] == "1.0.1"
    
    def test_get_base_context_default_title(self):
        """Test getting base context with default title."""
        from src.server.utils.template_helpers import get_base_context
        
        mock_request = MagicMock(spec=Request)
        context = get_base_context(mock_request)
        
        assert context["title"] == "Aniworld"
    
    def test_render_template_basic(self):
        """Test render_template function."""
        from src.server.utils.template_helpers import render_template
        
        mock_request = MagicMock(spec=Request)
        
        with patch('src.server.utils.template_helpers.templates.TemplateResponse') as mock_response:
            mock_response.return_value = "rendered"
            
            result = render_template("index.html", mock_request, title="Test")
            
            assert result == "rendered"
            mock_response.assert_called_once()
    
    def test_render_template_with_context(self):
        """Test render_template with additional context."""
        from src.server.utils.template_helpers import render_template
        
        mock_request = MagicMock(spec=Request)
        extra_context = {"user": "test_user", "is_authenticated": True}
        
        with patch('src.server.utils.template_helpers.templates.TemplateResponse') as mock_response:
            mock_response.return_value = "rendered"
            
            render_template("index.html", mock_request, context=extra_context)
            
            call_args = mock_response.call_args[0]
            context_arg = call_args[1]
            assert context_arg["user"] == "test_user"
            assert context_arg["is_authenticated"] is True
    
    def test_render_template_title_generation(self):
        """Test render_template generates title from template name."""
        from src.server.utils.template_helpers import render_template
        
        mock_request = MagicMock(spec=Request)
        
        with patch('src.server.utils.template_helpers.templates.TemplateResponse') as mock_response:
            mock_response.return_value = "rendered"
            
            render_template("index.html", mock_request)  # No title provided
            
            call_args = mock_response.call_args[0]
            context_arg = call_args[1]
            # Title should be generated from template name
            assert context_arg["title"] == "Index"


class TestValidateTemplateExists:
    """Test template existence validation."""
    
    def test_validate_template_exists_true(self, tmp_path):
        """Test validate_template_exists returns True for existing template."""
        from src.server.utils.template_helpers import validate_template_exists
        
        with patch('src.server.utils.template_helpers.TEMPLATES_DIR', tmp_path):
            template_file = tmp_path / "test.html"
            template_file.write_text("<html></html>")
            
            result = validate_template_exists("test.html")
            assert result is True
    
    def test_validate_template_exists_false(self, tmp_path):
        """Test validate_template_exists returns False for missing template."""
        from src.server.utils.template_helpers import validate_template_exists
        
        with patch('src.server.utils.template_helpers.TEMPLATES_DIR', tmp_path):
            result = validate_template_exists("nonexistent.html")
            assert result is False


class TestListAvailableTemplates:
    """Test listing available templates."""
    
    def test_list_available_templates(self, tmp_path):
        """Test listing available templates."""
        from src.server.utils.template_helpers import list_available_templates

        # Create test template files
        (tmp_path / "index.html").write_text("<html></html>")
        (tmp_path / "setup.html").write_text("<html></html>")
        (tmp_path / "README.md").write_text("# README")  # Should not be included
        
        with patch('src.server.utils.template_helpers.TEMPLATES_DIR', tmp_path):
            templates = list_available_templates()
        
        assert "index.html" in templates
        assert "setup.html" in templates
        assert "README.md" not in templates
        assert len(templates) == 2
    
    def test_list_available_templates_empty_directory(self, tmp_path):
        """Test listing templates from empty directory."""
        from src.server.utils.template_helpers import list_available_templates
        
        with patch('src.server.utils.template_helpers.TEMPLATES_DIR', tmp_path):
            templates = list_available_templates()
        
        assert templates == []
    
    def test_list_available_templates_missing_directory(self):
        """Test listing templates when directory doesn't exist."""
        from src.server.utils.template_helpers import list_available_templates
        
        with patch('src.server.utils.template_helpers.TEMPLATES_DIR', Path("/nonexistent")):
            templates = list_available_templates()
        
        assert templates == []


class TestPrepareSeriesContext:
    """Test series context preparation for templates."""
    
    def test_prepare_series_context_basic(self):
        """Test preparing basic series context."""
        from src.server.utils.template_helpers import prepare_series_context
        
        series_data = [
            {"key": "attack-on-titan", "name": "Attack on Titan", "folder": "AOT"},
            {"key": "one-piece", "name": "One Piece", "folder": "OP"}
        ]
        
        result = prepare_series_context(series_data)
        
        assert len(result) == 2
        assert result[0]["key"] == "attack-on-titan"
        assert result[0]["name"] == "Attack on Titan"
        assert result[0]["folder"] == "AOT"
    
    def test_prepare_series_context_sort_by_name(self):
        """Test preparing series context sorted by name."""
        from src.server.utils.template_helpers import prepare_series_context
        
        series_data = [
            {"key": "one-piece", "name": "One Piece", "folder": "OP"},
            {"key": "attack-on-titan", "name": "Attack on Titan", "folder": "AOT"},
            {"key": "death-note", "name": "Death Note", "folder": "DN"}
        ]
        
        result = prepare_series_context(series_data, sort_by="name")
        
        assert result[0]["name"] == "Attack on Titan"
        assert result[1]["name"] == "Death Note"
        assert result[2]["name"] == "One Piece"
    
    def test_prepare_series_context_sort_by_key(self):
        """Test preparing series context sorted by key."""
        from src.server.utils.template_helpers import prepare_series_context
        
        series_data = [
            {"key": "z-series", "name": "Z Series", "folder": "Z"},
            {"key": "a-series", "name": "A Series", "folder": "A"},
            {"key": "m-series", "name": "M Series", "folder": "M"}
        ]
        
        result = prepare_series_context(series_data, sort_by="key")
        
        assert result[0]["key"] == "a-series"
        assert result[1]["key"] == "m-series"
        assert result[2]["key"] == "z-series"
    
    def test_prepare_series_context_sort_by_folder(self):
        """Test preparing series context sorted by folder."""
        from src.server.utils.template_helpers import prepare_series_context
        
        series_data = [
            {"key": "series1", "name": "Series 1", "folder": "Z Folder"},
            {"key": "series2", "name": "Series 2", "folder": "A Folder"},
            {"key": "series3", "name": "Series 3", "folder": "M Folder"}
        ]
        
        result = prepare_series_context(series_data, sort_by="folder")
        
        assert result[0]["folder"] == "A Folder"
        assert result[1]["folder"] == "M Folder"
        assert result[2]["folder"] == "Z Folder"
    
    def test_prepare_series_context_empty_list(self):
        """Test preparing empty series context."""
        from src.server.utils.template_helpers import prepare_series_context
        
        result = prepare_series_context([])
        
        assert result == []
    
    def test_prepare_series_context_missing_key(self):
        """Test preparing series context with missing key field."""
        from src.server.utils.template_helpers import prepare_series_context
        
        series_data = [
            {"name": "No Key Series", "folder": "NoKey"},
            {"key": "valid-key", "name": "Valid Series", "folder": "Valid"}
        ]
        
        result = prepare_series_context(series_data)
        
        # Only the series with key should be included
        assert len(result) == 1
        assert result[0]["key"] == "valid-key"
    
    def test_prepare_series_context_default_values(self):
        """Test preparing series context fills in default values."""
        from src.server.utils.template_helpers import prepare_series_context
        
        series_data = [
            {"key": "minimal-series"}  # Missing name and folder
        ]
        
        result = prepare_series_context(series_data)
        
        assert result[0]["key"] == "minimal-series"
        assert result[0]["name"] == "minimal-series"  # Should use key as default
        assert result[0]["folder"] == ""  # Should default to empty string
    
    def test_prepare_series_context_extra_fields(self):
        """Test preparing series context preserves extra fields."""
        from src.server.utils.template_helpers import prepare_series_context
        
        series_data = [
            {
                "key": "series1",
                "name": "Series 1",
                "folder": "S1",
                "year": 2020,
                "status": "completed",
                "episodes": 12
            }
        ]
        
        result = prepare_series_context(series_data)
        
        assert result[0]["year"] == 2020
        assert result[0]["status"] == "completed"
        assert result[0]["episodes"] == 12


class TestGetSeriesByKey:
    """Test finding series by key."""
    
    def test_get_series_by_key_found(self):
        """Test getting series by key when found."""
        from src.server.utils.template_helpers import get_series_by_key
        
        series_data = [
            {"key": "attack-on-titan", "name": "Attack on Titan"},
            {"key": "one-piece", "name": "One Piece"}
        ]
        
        result = get_series_by_key(series_data, "attack-on-titan")
        
        assert result is not None
        assert result["name"] == "Attack on Titan"
    
    def test_get_series_by_key_not_found(self):
        """Test getting series by key when not found."""
        from src.server.utils.template_helpers import get_series_by_key
        
        series_data = [
            {"key": "attack-on-titan", "name": "Attack on Titan"}
        ]
        
        result = get_series_by_key(series_data, "nonexistent")
        
        assert result is None
    
    def test_get_series_by_key_empty_list(self):
        """Test getting series by key from empty list."""
        from src.server.utils.template_helpers import get_series_by_key
        
        result = get_series_by_key([], "any-key")
        
        assert result is None
    
    def test_get_series_by_key_case_sensitive(self):
        """Test that key matching is case-sensitive."""
        from src.server.utils.template_helpers import get_series_by_key
        
        series_data = [
            {"key": "Attack-on-Titan", "name": "Attack on Titan"}
        ]
        
        result = get_series_by_key(series_data, "attack-on-titan")
        
        assert result is None  # Different case should not match


class TestFilterSeriesByMissingEpisodes:
    """Test filtering series by missing episodes."""
    
    def test_filter_series_with_missing_episodes(self):
        """Test filtering series with missing episodes."""
        from src.server.utils.template_helpers import filter_series_by_missing_episodes
        
        series_data = [
            {
                "key": "series1",
                "name": "Series 1",
                "missing_episodes": {"season_1": [1, 2, 3]}
            },
            {
                "key": "series2",
                "name": "Series 2",
                "missing_episodes": {"season_1": []}
            },
            {
                "key": "series3",
                "name": "Series 3",
                "missing_episodes": {"season_1": [5]}
            }
        ]
        
        result = filter_series_by_missing_episodes(series_data)
        
        assert len(result) == 2
        assert result[0]["key"] == "series1"
        assert result[1]["key"] == "series3"
    
    def test_filter_series_no_missing_episodes(self):
        """Test filtering when no series have missing episodes."""
        from src.server.utils.template_helpers import filter_series_by_missing_episodes
        
        series_data = [
            {
                "key": "series1",
                "name": "Series 1",
                "missing_episodes": {"season_1": []}
            },
            {
                "key": "series2",
                "name": "Series 2",
                "missing_episodes": {}
            }
        ]
        
        result = filter_series_by_missing_episodes(series_data)
        
        assert len(result) == 0
    
    def test_filter_series_empty_list(self):
        """Test filtering empty series list."""
        from src.server.utils.template_helpers import filter_series_by_missing_episodes
        
        result = filter_series_by_missing_episodes([])
        
        assert len(result) == 0
    
    def test_filter_series_missing_field(self):
        """Test filtering when missing_episodes field is missing."""
        from src.server.utils.template_helpers import filter_series_by_missing_episodes
        
        series_data = [
            {"key": "series1", "name": "Series 1"}  # No missing_episodes
        ]
        
        result = filter_series_by_missing_episodes(series_data)
        
        # Should not crash and should not include this series
        assert len(result) == 0
    
    def test_filter_series_multiple_seasons(self):
        """Test filtering with multiple seasons."""
        from src.server.utils.template_helpers import filter_series_by_missing_episodes
        
        series_data = [
            {
                "key": "series1",
                "name": "Series 1",
                "missing_episodes": {
                    "season_1": [1, 2],
                    "season_2": []
                }
            }
        ]
        
        result = filter_series_by_missing_episodes(series_data)
        
        # Should include because season_1 has missing episodes
        assert len(result) == 1
