"""File content validation and format detection.

Provides file format detection, structure validation, and metadata extraction
for extending file operation capabilities in the future.
"""

import re
from pathlib import Path
from typing import (
    Any,
    Dict,
    Optional,
    Tuple,
)

from sseed.exceptions import FileError
from sseed.logging_config import get_logger

logger = get_logger(__name__)


def detect_file_format(file_path: str) -> str:
    """Detect if file contains BIP-39 mnemonic or SLIP-39 shards.

    Args:
        file_path: Path to the file to analyze.

    Returns:
        File format type: 'bip39', 'slip39', or 'unknown'.

    Raises:
        FileError: If file cannot be read.
    """
    try:
        file_path_obj = Path(file_path)

        if not file_path_obj.exists():
            raise FileError(f"File not found: {file_path}")

        with open(file_path_obj, encoding="utf-8") as f:
            content = f.read()

        # Check for BIP-39 header comment
        if "# BIP-39 Mnemonic File" in content:
            return "bip39"

        # Check for SLIP-39 headers
        if any(
            header in content
            for header in ["# SLIP-39 Shard File", "# SLIP-39 Shards File"]
        ):
            return "slip39"

        # Analyze content structure
        non_comment_lines = count_non_comment_lines(content)

        # Single line suggests BIP-39 mnemonic
        if non_comment_lines == 1:
            return "bip39"

        # Multiple lines suggest SLIP-39 shards
        if non_comment_lines > 1:
            return "slip39"

        return "unknown"

    except Exception as e:
        error_msg = f"Failed to detect file format for {file_path}: {e}"
        logger.error(error_msg)
        raise FileError(error_msg) from e


def validate_file_structure(  # pylint: disable=too-many-return-statements
    file_path: str,
) -> Tuple[bool, Optional[str]]:
    """Validate file structure and return error message if invalid.

    Args:
        file_path: Path to the file to validate.

    Returns:
        Tuple of (is_valid, error_message). Error message is None if valid.
    """
    try:
        file_path_obj = Path(file_path)

        if not file_path_obj.exists():
            return False, f"File not found: {file_path}"

        if not file_path_obj.is_file():
            return False, f"Path is not a file: {file_path}"

        with open(file_path_obj, encoding="utf-8") as f:
            content = f.read().strip()

        if not content:
            return False, f"File is empty: {file_path}"

        # Count non-comment lines
        non_comment_lines = count_non_comment_lines(content)

        if non_comment_lines == 0:
            return False, f"File contains no content lines: {file_path}"

        # Validate UTF-8 encoding (already validated by successful read)
        return True, None

    except UnicodeDecodeError:
        return False, f"File is not valid UTF-8: {file_path}"
    except Exception as e:  # pylint: disable=broad-exception-caught
        return False, f"Error validating file structure: {e}"


def count_non_comment_lines(content: str) -> int:
    """Count non-comment lines in file content.

    Args:
        content: File content as string.

    Returns:
        Number of non-comment, non-empty lines.
    """
    count = 0
    for line in content.split("\n"):
        line = line.strip()
        if line and not line.startswith("#"):
            count += 1
    return count


def extract_metadata_from_comments(content: str) -> Dict[str, Any]:
    """Extract metadata from comment headers.

    Args:
        content: File content as string.

    Returns:
        Dictionary of extracted metadata.
    """
    metadata: Dict[str, Any] = {}

    for line in content.split("\n"):
        line = line.strip()
        if not line.startswith("#"):
            continue

        # Remove leading '#' and strip
        comment = line[1:].strip()

        # Extract file type
        if "BIP-39 Mnemonic File" in comment:
            metadata["file_type"] = "bip39"
        elif "SLIP-39 Shard File" in comment:
            metadata["file_type"] = "slip39_single"
        elif "SLIP-39 Shards File" in comment:
            metadata["file_type"] = "slip39_multi"

        # Extract generation timestamp
        timestamp_match = re.search(r"Generated by sseed on ([\d\-: ]+)", comment)
        if timestamp_match:
            metadata["generated_at"] = timestamp_match.group(1)

        # Extract shard information
        shard_match = re.search(r"Shard (\d+) of (\d+)", comment)
        if shard_match:
            metadata["shard_number"] = int(shard_match.group(1))
            metadata["total_shards"] = int(shard_match.group(2))

        # Extract shard count for multi-shard files
        count_match = re.search(r"Contains (\d+) SLIP-39 shards", comment)
        if count_match:
            metadata["shard_count"] = int(count_match.group(1))

    return metadata


def validate_utf8_encoding(file_path: str) -> Tuple[bool, Optional[str]]:
    """Validate that file has valid UTF-8 encoding.

    Args:
        file_path: Path to the file to validate.

    Returns:
        Tuple of (is_valid, error_message). Error message is None if valid.
    """
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            f.read()
        return True, None
    except UnicodeDecodeError as e:
        return False, f"Invalid UTF-8 encoding: {e}"
    except Exception as e:  # pylint: disable=broad-exception-caught
        return False, f"Error reading file: {e}"


def check_file_permissions(file_path: str) -> Tuple[bool, Optional[str]]:
    """Check if file has appropriate permissions for reading.

    Args:
        file_path: Path to the file to check.

    Returns:
        Tuple of (has_permissions, error_message). Error message is None if valid.
    """
    try:
        file_path_obj = Path(file_path)

        if not file_path_obj.exists():
            return False, f"File does not exist: {file_path}"

        if not file_path_obj.is_file():
            return False, f"Path is not a file: {file_path}"

        # Try to read the file to check permissions
        with open(file_path_obj, "r", encoding="utf-8") as f:
            f.read(1)  # Read just one character to test permissions

        return True, None

    except PermissionError:
        return False, f"Permission denied reading file: {file_path}"
    except Exception as e:  # pylint: disable=broad-exception-caught
        return False, f"Error checking file permissions: {e}"
