# -*- coding: utf-8 -*-
import unicodedata


class FileProcessor:
    """Base class for file processor"""

    @staticmethod
    def can_handle(file_path: str) -> bool:
        """Determine if the file can be processed"""
        raise NotImplementedError

    @staticmethod
    def extract_text(file_path: str) -> str:
        """Extract file text content"""
        raise NotImplementedError


class TextFileProcessor(FileProcessor):
    """Text file processor"""

    ENCODINGS = ["utf-8", "gbk", "gb2312", "latin1"]
    SAMPLE_SIZE = 8192  # Read the first 8KB to detect encoding

    @staticmethod
    def can_handle(file_path: str) -> bool:
        """Determine if the file is a text file by trying to decode it"""
        try:
            # Read the first part of the file to detect encoding
            with open(file_path, "rb") as f:
                sample = f.read(TextFileProcessor.SAMPLE_SIZE)

            # Check if it contains null bytes (usually represents a binary file)
            if b"\x00" in sample:
                return False

            # Check if it contains too many non-printable characters (usually represents a binary file)
            non_printable = sum(
                1 for byte in sample if byte < 32 and byte not in (9, 10, 13)
            )  # tab, newline, carriage return
            if (
                non_printable / len(sample) > 0.3
            ):  # If non-printable characters exceed 30%, it is considered a binary file
                return False

            # Try to decode with different encodings
            for encoding in TextFileProcessor.ENCODINGS:
                try:
                    sample.decode(encoding)
                    return True
                except UnicodeDecodeError:
                    continue

            return False

        except Exception:
            return False

    @staticmethod
    def extract_text(file_path: str) -> str:
        """Extract text content, using the detected correct encoding"""
        detected_encoding = None
        try:
            # First try to detect encoding
            with open(file_path, "rb") as f:
                raw_data = f.read()

            # Try different encodings
            for encoding in TextFileProcessor.ENCODINGS:
                try:
                    raw_data.decode(encoding)
                    detected_encoding = encoding
                    break
                except UnicodeDecodeError:
                    continue

            if not detected_encoding:
                raise UnicodeDecodeError(f"Failed to decode file with supported encodings: {file_path}")  # type: ignore

            # Use the detected encoding to read the file
            with open(file_path, "r", encoding=detected_encoding, errors="ignore") as f:
                content = f.read()

            # Normalize Unicode characters
            content = unicodedata.normalize("NFKC", content)

            return content

        except Exception as e:
            raise Exception(f"Failed to read file: {str(e)}")
