"""Unit tests for path and URL validation functionality."""

import os
import tempfile
from pathlib import Path
import pytest

from src.security.secure_config import (
    validate_path,
    validate_youtube_url,
    sanitize_filename,
)


class TestPathValidation:
    """Test cases for path validation functions."""

    def setup_method(self):
        """Set up test fixtures."""
        self.temp_dir = tempfile.mkdtemp()
        self.test_file = Path(self.temp_dir) / "test.txt"
        self.test_file.write_text("test content")

    def teardown_method(self):
        """Clean up test fixtures."""
        import shutil
        if self.temp_dir and os.path.exists(self.temp_dir):
            shutil.rmtree(self.temp_dir)

    def test_validate_path_allows_user_directories(self):
        """Test that validate_path allows paths in user directories."""
        user_dirs = [
            "~/Documents",
            "~/Downloads",
            "~/Desktop",
            "~/Music",
            "~/Videos",
            "~/.trax",
        ]
        
        for user_dir in user_dirs:
            test_path = f"{user_dir}/test_file.txt"
            assert validate_path(test_path) is True

    def test_validate_path_blocks_directory_traversal(self):
        """Test that validate_path blocks directory traversal attempts."""
        malicious_paths = [
            "../../../etc/passwd",
            "~/Documents/../../../etc/shadow",
            "/tmp/../../../root/.ssh/id_rsa",
            "~/Downloads/..//..//..//var/log/auth.log",
            "~/Desktop/../../../../etc/hosts",
        ]
        
        for path in malicious_paths:
            assert validate_path(path) is False

    def test_validate_path_blocks_system_directories(self):
        """Test that validate_path blocks access to system directories."""
        system_paths = [
            "/etc/passwd",
            "/var/log/auth.log",
            "/root/.ssh/id_rsa",
            "/tmp/malicious_file",
            "/usr/bin/evil",
            "/bin/bash",
        ]
        
        for path in system_paths:
            assert validate_path(path) is False

    def test_validate_path_allows_current_directory(self):
        """Test that validate_path allows paths in current working directory."""
        # Create a file in current directory
        test_file = "test_current_dir.txt"
        with open(test_file, "w") as f:
            f.write("test")
        
        try:
            assert validate_path(test_file) is True
            assert validate_path("./test_current_dir.txt") is True
            assert validate_path("../test_current_dir.txt") is False
        finally:
            os.remove(test_file)

    def test_validate_path_handles_edge_cases(self):
        """Test that validate_path handles edge cases properly."""
        edge_cases = [
            "",  # Empty string
            None,  # None value
            "   ",  # Whitespace only
            ".",  # Current directory
            "..",  # Parent directory
        ]
        
        for path in edge_cases:
            assert validate_path(path) is False

    def test_validate_path_handles_absolute_paths(self):
        """Test that validate_path handles absolute paths correctly."""
        # Test with actual user home directory
        home = os.path.expanduser("~")
        safe_absolute_paths = [
            f"{home}/Documents/test.txt",
            f"{home}/Downloads/file.mp4",
            f"{home}/.trax/config.json",
        ]
        
        for path in safe_absolute_paths:
            assert validate_path(path) is True

    def test_validate_path_handles_special_characters(self):
        """Test that validate_path handles special characters in paths."""
        special_paths = [
            "~/Documents/file with spaces.txt",
            "~/Downloads/file-with-dashes.mp4",
            "~/Desktop/file_with_underscores.pdf",
            "~/Music/song (remix).mp3",
        ]
        
        for path in special_paths:
            assert validate_path(path) is True


class TestURLValidation:
    """Test cases for URL validation functions."""

    def test_validate_youtube_url_allows_valid_urls(self):
        """Test that validate_youtube_url allows valid YouTube URLs."""
        valid_urls = [
            "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
            "https://youtu.be/dQw4w9WgXcQ",
            "http://www.youtube.com/watch?v=dQw4w9WgXcQ",
            "https://youtube.com/watch?v=dQw4w9WgXcQ",
            "https://www.youtube.com/embed/dQw4w9WgXcQ",
            "https://www.youtube.com/v/dQw4w9WgXcQ",
            "https://www.youtube.com/playlist?list=PL123456",
        ]
        
        for url in valid_urls:
            assert validate_youtube_url(url) is True

    def test_validate_youtube_url_blocks_invalid_urls(self):
        """Test that validate_youtube_url blocks invalid URLs."""
        invalid_urls = [
            "https://www.google.com",
            "https://malicious-site.com/fake-youtube",
            "ftp://youtube.com/video",
            "javascript:alert('xss')",
            "data:text/html,<script>alert('xss')</script>",
            "file:///etc/passwd",
            "https://www.youtube.com.evil.com/watch?v=123",
            "https://youtube.com.evil.com/watch?v=123",
        ]
        
        for url in invalid_urls:
            assert validate_youtube_url(url) is False

    def test_validate_youtube_url_handles_edge_cases(self):
        """Test that validate_youtube_url handles edge cases."""
        edge_cases = [
            "",  # Empty string
            None,  # None value
            "not_a_url",  # Plain text
            "youtube.com",  # Missing protocol
            "https://",  # Incomplete URL
            "https://youtube.com",  # Missing path
        ]
        
        for url in edge_cases:
            assert validate_youtube_url(url) is False

    def test_validate_youtube_url_handles_complex_urls(self):
        """Test that validate_youtube_url handles complex YouTube URLs."""
        complex_urls = [
            "https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=30s",
            "https://youtu.be/dQw4w9WgXcQ?t=30",
            "https://www.youtube.com/watch?v=dQw4w9WgXcQ&list=PL123456&index=1",
            "https://www.youtube.com/watch?v=dQw4w9WgXcQ&feature=share",
            "https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=1",
        ]
        
        for url in complex_urls:
            assert validate_youtube_url(url) is True

    def test_validate_youtube_url_handles_different_protocols(self):
        """Test that validate_youtube_url handles different protocols."""
        protocols = [
            "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
            "http://www.youtube.com/watch?v=dQw4w9WgXcQ",
            "https://youtu.be/dQw4w9WgXcQ",
            "http://youtu.be/dQw4w9WgXcQ",
        ]
        
        for url in protocols:
            assert validate_youtube_url(url) is True

    def test_validate_youtube_url_handles_subdomains(self):
        """Test that validate_youtube_url handles YouTube subdomains."""
        subdomain_urls = [
            "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
            "https://m.youtube.com/watch?v=dQw4w9WgXcQ",
            "https://music.youtube.com/watch?v=dQw4w9WgXcQ",
        ]
        
        for url in subdomain_urls:
            assert validate_youtube_url(url) is True


class TestFilenameSanitization:
    """Test cases for filename sanitization."""

    def test_sanitize_filename_removes_dangerous_characters(self):
        """Test that sanitize_filename removes dangerous characters."""
        dangerous_filenames = [
            "file<>:\"/\\|?*.txt",
            "file with spaces.txt",
            "file.with.dots.txt",
            "file with (parentheses).txt",
            "file with [brackets].txt",
            "file with {braces}.txt",
        ]
        
        for filename in dangerous_filenames:
            sanitized = sanitize_filename(filename)
            assert "<" not in sanitized
            assert ">" not in sanitized
            assert ":" not in sanitized
            assert '"' not in sanitized
            assert "/" not in sanitized
            assert "\\" not in sanitized
            assert "|" not in sanitized
            assert "?" not in sanitized
            assert "*" not in sanitized

    def test_sanitize_filename_handles_edge_cases(self):
        """Test that sanitize_filename handles edge cases."""
        edge_cases = [
            "",  # Empty string
            None,  # None value
            "   ",  # Whitespace only
            ".",  # Just a dot
            "..",  # Just dots
            "   .   ",  # Whitespace and dots
        ]
        
        for filename in edge_cases:
            sanitized = sanitize_filename(filename)
            assert sanitized == "unnamed_file"

    def test_sanitize_filename_preserves_safe_characters(self):
        """Test that sanitize_filename preserves safe characters."""
        safe_filenames = [
            "normal_file.txt",
            "file_with_underscores.txt",
            "file-with-dashes.txt",
            "file123.txt",
            "FILE.TXT",
            "file.txt",
        ]
        
        for filename in safe_filenames:
            sanitized = sanitize_filename(filename)
            assert sanitized == filename

    def test_sanitize_filename_limits_length(self):
        """Test that sanitize_filename limits filename length."""
        long_filename = "a" * 300 + ".txt"
        sanitized = sanitize_filename(long_filename)
        assert len(sanitized) <= 255
        assert sanitized.endswith(".txt")

    def test_sanitize_filename_removes_leading_trailing_dots(self):
        """Test that sanitize_filename removes leading and trailing dots."""
        dot_filenames = [
            ".hidden_file.txt",
            "file.txt.",
            ".file.txt.",
            "...file.txt...",
        ]
        
        expected_results = [
            "hidden_file.txt",
            "file.txt",
            "file.txt",
            "file.txt",
        ]
        
        for filename, expected in zip(dot_filenames, expected_results):
            sanitized = sanitize_filename(filename)
            assert sanitized == expected

    def test_sanitize_filename_handles_multiple_extensions(self):
        """Test that sanitize_filename handles multiple extensions."""
        multi_ext_filenames = [
            "file.txt.bak",
            "file.tar.gz",
            "file.backup.old",
        ]
        
        for filename in multi_ext_filenames:
            sanitized = sanitize_filename(filename)
            assert sanitized == filename
