"""
Test suite for file utility functions.
"""

import os
import tempfile
from pathlib import Path

import pytest
from markitect_utils.file_utils import (
    safe_filename,
    ensure_extension,
    get_file_size,
    is_text_file,
    normalize_path,
)


class TestSafeFilename:
    """Test cases for the safe_filename function."""

    def test_basic_sanitization(self):
        """Test basic filename sanitization."""
        assert safe_filename("normal_file.txt") == "normal_file.txt"
        assert safe_filename("file with spaces.txt") == "file with spaces.txt"

    def test_unsafe_characters(self):
        """Test removal of unsafe characters."""
        assert safe_filename("file<>name.txt") == "file__name.txt"
        assert safe_filename('file"name.txt') == "file_name.txt"
        assert safe_filename("file/path\\name.txt") == "file_path_name.txt"
        assert safe_filename("file|name.txt") == "file_name.txt"

    def test_custom_replacement(self):
        """Test custom replacement character."""
        assert safe_filename("file<>name.txt", "-") == "file--name.txt"
        assert safe_filename("file/path\\name.txt", "") == "filepathname.txt"

    def test_reserved_names(self):
        """Test handling of Windows reserved names."""
        assert safe_filename("CON") == "file_CON"
        assert safe_filename("PRN.txt") == "file_PRN.txt"
        assert safe_filename("COM1") == "file_COM1"
        assert safe_filename("con") == "file_con"  # case insensitive

    def test_edge_cases(self):
        """Test edge cases."""
        assert safe_filename("") == ""  # Empty input returns empty
        assert safe_filename("   ") == "file_"  # Whitespace only gets prefix
        assert safe_filename("...") == "file_"  # Dots only gets prefix
        assert safe_filename(".hidden") == "hidden"  # Leading dot gets stripped


class TestEnsureExtension:
    """Test cases for the ensure_extension function."""

    def test_add_extension(self):
        """Test adding extension to filename."""
        assert ensure_extension("document", ".md") == "document.md"
        assert ensure_extension("file", "txt") == "file.txt"

    def test_existing_extension(self):
        """Test when extension already exists."""
        assert ensure_extension("document.md", ".md") == "document.md"
        assert ensure_extension("file.txt", "txt") == "file.txt"

    def test_different_extension(self):
        """Test adding extension when different one exists."""
        assert ensure_extension("document.txt", ".md") == "document.txt.md"
        assert ensure_extension("file.doc", "pdf") == "file.doc.pdf"

    def test_edge_cases(self):
        """Test edge cases."""
        assert ensure_extension("", ".md") == ""
        assert ensure_extension("file", "") == "file"
        assert ensure_extension("file.md", "") == "file.md"


class TestGetFileSize:
    """Test cases for the get_file_size function."""

    def test_existing_file(self):
        """Test getting size of existing file."""
        with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
            f.write("Hello, World!")
            temp_path = f.name

        try:
            size = get_file_size(temp_path)
            assert size is not None
            assert size > 0
        finally:
            os.unlink(temp_path)

    def test_nonexistent_file(self):
        """Test getting size of non-existent file."""
        assert get_file_size("/path/that/does/not/exist") is None

    def test_empty_file(self):
        """Test getting size of empty file."""
        with tempfile.NamedTemporaryFile(delete=False) as f:
            temp_path = f.name

        try:
            size = get_file_size(temp_path)
            assert size == 0
        finally:
            os.unlink(temp_path)

    def test_path_object(self):
        """Test with Path object."""
        with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
            f.write("test content")
            temp_path = Path(f.name)

        try:
            size = get_file_size(temp_path)
            assert size is not None
            assert size > 0
        finally:
            os.unlink(temp_path)


class TestIsTextFile:
    """Test cases for the is_text_file function."""

    def test_text_file(self):
        """Test with actual text file."""
        with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt') as f:
            f.write("This is a text file with some content.")
            temp_path = f.name

        try:
            assert is_text_file(temp_path) is True
        finally:
            os.unlink(temp_path)

    def test_binary_file(self):
        """Test with binary file."""
        with tempfile.NamedTemporaryFile(mode='wb', delete=False, suffix='.bin') as f:
            f.write(b'\x00\x01\x02\x03\x04\x05')
            temp_path = f.name

        try:
            assert is_text_file(temp_path) is False
        finally:
            os.unlink(temp_path)

    def test_empty_file(self):
        """Test with empty file."""
        with tempfile.NamedTemporaryFile(delete=False) as f:
            temp_path = f.name

        try:
            assert is_text_file(temp_path) is True  # Empty files are considered text
        finally:
            os.unlink(temp_path)

    def test_unicode_file(self):
        """Test with Unicode text file."""
        with tempfile.NamedTemporaryFile(mode='w', delete=False, encoding='utf-8') as f:
            f.write("Hello 世界! This is UTF-8 text.")
            temp_path = f.name

        try:
            assert is_text_file(temp_path) is True
        finally:
            os.unlink(temp_path)

    def test_nonexistent_file(self):
        """Test with non-existent file."""
        assert is_text_file("/path/that/does/not/exist") is False


class TestNormalizePath:
    """Test cases for the normalize_path function."""

    def test_relative_path(self):
        """Test normalizing relative paths."""
        # Note: These tests are environment-dependent
        result = normalize_path("./test")
        assert os.path.isabs(result)
        assert result.endswith("test")

    def test_path_with_dots(self):
        """Test path with dot components."""
        result = normalize_path("./dir/../file.txt")
        assert os.path.isabs(result)
        assert result.endswith("file.txt")

    def test_already_absolute(self):
        """Test already absolute path."""
        abs_path = "/tmp/test/file.txt"
        result = normalize_path(abs_path)
        assert result == abs_path

    def test_path_object(self):
        """Test with Path object."""
        path_obj = Path("./test/file.txt")
        result = normalize_path(path_obj)
        assert os.path.isabs(result)
        assert isinstance(result, str)

    def test_edge_cases(self):
        """Test edge cases."""
        assert normalize_path("") == ""

        # Current directory should normalize to absolute path
        result = normalize_path(".")
        assert os.path.isabs(result)