"""
Spark Simplicity - Path Validation Utilities
============================================

Comprehensive path validation and management utilities for secure and reliable I/O operations.
This module provides production-grade path validation, permission checking, and mount point
management capabilities essential for enterprise data processing workflows. Ensures robust
file system operations across different platforms and storage systems.

Key Features:
    - **Cross-Platform Path Handling**: Windows, Linux, and macOS path processing
    - **Mount Point Detection**: Automatic shared storage mount point identification
    - **Permission Validation**: Comprehensive read/write permission checking
    - **Spark Integration**: Native Spark path configuration and cluster validation
    - **Network Storage Support**: NFS, HDFS, and cloud storage compatibility
    - **Error Recovery**: Detailed error reporting with actionable failure information

Path Security:
    - **Access Control**: Validates file and directory permissions before operations
    - **Mount Validation**: Ensures shared storage accessibility across cluster nodes
    - **Privilege Validation**: Checks current process permissions against required operations
    - **Cluster Verification**: Validates path accessibility on all Spark executors

Enterprise Features:
    - **Audit Logging**: Comprehensive logging of all path operations and validations
    - **Failure Analysis**: Detailed error messages with troubleshooting guidance
    - **Mount Point Discovery**: Automatic detection of shared storage configurations
    - **Cluster Coordination**: Ensures consistent path access across distributed nodes

Usage:
    These utilities are used internally by all I/O operations in Spark Simplicity
    to ensure reliable and secure file system access across different environments
    and storage systems, with special focus on distributed Spark clusters.

    from spark_simplicity.io.validation.path_utils import configure_spark_path
"""

import os
from pathlib import Path
from typing import Optional, Tuple, Union

from pyspark.sql import SparkSession

from ...logger import get_logger

# Logger for path utilities
_path_logger = get_logger("spark_simplicity.io.path")


def _extract_mount_point(file_path: Union[str, Path]) -> Optional[Path]:
    """
    Extract shared storage mount point from file path for cluster validation.

    Analyzes file paths to automatically detect shared storage mount points that
    require cluster-wide accessibility validation. This function identifies common
    mount point patterns used in enterprise environments for NFS, HDFS, and other
    distributed storage systems.

    Args:
        file_path: File path to analyze for mount point extraction. Can be a string
                  or Path object representing either absolute or relative paths.

    Returns:
        Path object pointing to the detected mount point if the path follows
        standard mount point conventions (minimum 3 path components), or None
        if the path doesn't appear to be on a shared mount.

    Mount Point Detection Logic:
        - Requires minimum 3 path components: root, mount prefix, mount name
        - Examples of valid mount points: /mnt/shared, /nfs/data, /hdfs/warehouse
        - Windows UNC paths and drive letters are not considered mount points
        - Returns the first three path components as the mount point

    Examples:
        Standard Unix mount point detection:

         _extract_mount_point("/mnt/shared/data/file.csv")
        Path("/mnt/shared")

         _extract_mount_point("/nfs/warehouse/tables/users.parquet")
        Path("/nfs/warehouse")

        Non-mount point paths return None:

         _extract_mount_point("C:\\data\\file.csv")  # Windows drive
        None

         _extract_mount_point("/home/user/local.txt")  # Standard system path
        Path("/home/user")  # May not be a true mount point

         _extract_mount_point("relative/path.json")  # Relative path
        None

    Use Cases:
        - Automatic detection of shared storage in cluster environments
        - Validation that files are accessible across all Spark executors
        - Configuration of appropriate Spark path schemes (file:// vs direct paths)
        - Enterprise storage system integration and validation

    Note:
        This function performs heuristic mount point detection based on path
        structure. It may identify system directories as mount points if they
        follow the expected pattern. Use in conjunction with actual mount point
        validation for production deployments.
    """
    path = Path(file_path)
    parts = path.parts

    # Minimum required parts: /, mount_prefix, mount_name
    if len(parts) < 3:
        return None

    return Path(*parts[:3])


def _check_path_access(path: Path, path_type: str = "path") -> Tuple[bool, str]:
    """
    Check if path exists and is accessible with comprehensive validation.

    Performs thorough accessibility checks including existence verification,
    permission validation, and type-specific requirements. This function provides
    detailed error reporting to help diagnose path access issues in enterprise
    environments with complex permission structures.

    Args:
        path: Path object to validate for accessibility. Can represent files,
              directories, or mount points depending on the path_type parameter.
        path_type: Descriptive type identifier used in error messages for context.
                  Common values: "path", "mount point", "input file", "output directory".
                  This helps provide specific error messages for different use cases.

    Returns:
        Tuple containing (success_flag, error_message):
        - success_flag: Boolean indicating whether the path is accessible
        - error_message: Empty string on success, detailed error description on failure

    Validation Checks:
        1. **Existence Check**: Verifies the path exists on the filesystem
        2. **Type Validation**: For "mount point" type, ensures path is a directory
        3. **Permission Check**: Validates current process has read access to the path
        4. **Accessibility Test**: Confirms path can be accessed without errors

    Error Scenarios:
        - **Path Not Found**: Returns specific message with full path for debugging
        - **Type Mismatch**: For mount points, ensures directory type requirement
        - **Permission Denied**: Identifies insufficient read permissions
        - **Access Errors**: Handles other filesystem-level access issues

    Examples:
        File accessibility check:

         success, error = _check_path_access(Path("/data/input.csv"), "input file")
         if not success:
        ...     print(f"Access failed: {error}")

        Directory accessibility check:

         success, error = _check_path_access(Path("/mnt/shared"), "mount point")
         # Ensures path exists, is directory, and is readable

        Generic path check:

         success, error = _check_path_access(Path("/some/path"))
         # Uses default "path" type description

    Cross-Platform Considerations:
        - **Unix/Linux**: Uses POSIX permission model with os.access()
        - **Windows**: Handles Windows ACL permissions and drive accessibility
        - **Network Storage**: Compatible with NFS, SMB, and other network filesystems
        - **Symbolic Links**: Follows links to check actual target accessibility

    Performance Notes:
        - Minimal overhead for local filesystem checks
        - Network paths may have additional latency
        - Results should be cached for repeated access checks
        - Function is thread-safe for concurrent validation

    Note:
        This function is used internally by path validation routines to provide
        consistent error reporting and validation logic across all I/O operations.
        The detailed error messages help administrators diagnose and resolve
        access issues in complex enterprise storage environments.
    """
    if not path.exists():
        return False, f"{path_type} does not exist: {path}"

    if not path.is_dir() and path_type == "mount point":
        return False, f"{path_type} is not a directory: {path}"

    if not os.access(path, os.R_OK):
        return False, f"no read access to {path_type}: {path}"

    return True, ""


def configure_spark_path(
    file_path: Path, shared_mount: bool, spark: SparkSession
) -> str:
    """
    Configure optimal Spark path format with cluster-wide validation for reliable distributed I/O operations.

    Determines the appropriate path format for Spark I/O operations based on storage type and validates
    accessibility across all cluster nodes. This function ensures that file paths work correctly in
    distributed Spark environments by choosing between direct path access for shared storage and
    file URI schemes for local files, while performing comprehensive cluster validation.

    Path Configuration Strategy:
        - **Shared Mount Storage**: Uses direct path format for cluster-accessible storage systems
          like NFS, HDFS, or shared network drives. Performs cluster-wide validation to ensure
          all executor nodes can access the path before proceeding with I/O operations.

        - **Local File Storage**: Uses file:// URI scheme for local-only files that exist on
          individual nodes. Appropriate for single-node Spark deployments or when files are
          replicated to all nodes independently.

    Args:
        file_path: Path object representing the target file or directory location. Can point
                  to input files for reading or output locations for writing operations.
                  The path format is automatically configured based on the shared_mount parameter.
        shared_mount: Boolean flag indicating whether the file path resides on shared storage
                     accessible by all cluster nodes. True triggers cluster-wide validation
                     to ensure distributed accessibility. False uses local file URI scheme.
        spark: Active SparkSession instance used for cluster validation operations. The session
              is used to test path accessibility across all executor nodes when shared_mount=True.

    Returns:
        Properly formatted path string optimized for Spark I/O operations:
        - For shared mounts: Direct string path (e.g., "/mnt/shared/data/file.parquet")
        - For local files: File URI scheme (e.g., "file:///home/user/local/file.csv")

    Raises:
        RuntimeError: If shared mount validation fails, indicating the path is not accessible
                     on all cluster nodes. The error provides detailed troubleshooting guidance
                     including specific actions required to resolve cluster accessibility issues.
                     Common causes include unmounted storage, permission problems, or network
                     connectivity issues between cluster nodes.

    Cluster Validation Process:
        When shared_mount=True, performs comprehensive validation:
        1. **Path Existence**: Verifies the path exists on the driver node
        2. **Mount Point Detection**: Identifies shared storage mount points automatically
        3. **Executor Testing**: Tests path accessibility from all Spark executor nodes
        4. **Permission Validation**: Confirms read/write permissions across the cluster
        5. **Network Connectivity**: Validates network filesystem accessibility

    Performance Considerations:
        - **Shared Mount Validation**: Involves network communication with all executors
        - **Validation Caching**: Results should be cached for repeated path operations
        - **Network Latency**: Mount point validation may have network filesystem latency
        - **Cluster Size**: Validation time scales with number of executor nodes

    Examples:
        Configure path for shared NFS storage with cluster validation:

         spark_path = configure_spark_path(
        ...     Path("/nfs/data/input.parquet"),
        ...     shared_mount=True,
        ...     spark=spark_session
        ... )
         print(spark_path)
        "/nfs/data/input.parquet"

        Configure path for local file with URI scheme:

         spark_path = configure_spark_path(
        ...     Path("/home/user/local.csv"),
        ...     shared_mount=False,
        ...     spark=spark_session
        ... )
         print(spark_path)
        "file:///home/user/local.csv"

        Handle validation failure for inaccessible shared mount:

         try:
        ...     spark_path = configure_spark_path(
        ...         Path("/unavailable/mount/data.json"),
        ...         shared_mount=True,
        ...         spark=spark_session
        ...     )
        ... except RuntimeError as e:
        ...     print(f"Mount validation failed: {e}")

    Storage Type Guidelines:
        **Shared Storage (shared_mount=True)**:
        - NFS (Network File System) mounts
        - HDFS (Hadoop Distributed File System)
        - Cloud storage mounts (S3, Azure, GCS)
        - Shared network drives (SMB/CIFS)
        - Cluster-replicated storage systems

        **Local Storage (shared_mount=False)**:
        - Local disk files on individual nodes
        - Node-specific temporary directories
        - Single-node Spark deployments
        - Files replicated independently to each node

    Troubleshooting Mount Validation Failures:
        When cluster validation fails, check:
        1. **Mount Status**: Ensure shared storage is mounted on ALL worker nodes
        2. **Permissions**: Verify Spark processes have read/write access
        3. **Network**: Test network connectivity between nodes and storage
        4. **Consistency**: Confirm filesystem consistency across all nodes
        5. **Alternative**: Copy files to HDFS for guaranteed distributed access

    See Also:
        - ``_extract_mount_point()``: Mount point detection logic
        - ``_check_path_access()``: Individual node path validation
        - Mount validator module: Cluster-wide mount point validation

    Note:
        This function is critical for ensuring reliable I/O operations in distributed
        Spark environments. Proper path configuration prevents common issues like
        FileNotFoundException on executor nodes or data corruption due to inconsistent
        file system access patterns across the cluster.
    """
    if shared_mount:
        # Import here to avoid circular imports
        from .mount_validator import _validate_mount_point

        # Validate mount point accessibility across cluster
        if not _validate_mount_point(spark, file_path):
            raise RuntimeError(
                f"Mount point validation failed for: {file_path}\n"
                f"CRITICAL: Mount point is not accessible on all cluster nodes.\n"
                f"Required actions:\n"
                f"   1. Mount the shared storage on ALL Spark worker nodes\n"
                f"   2. Ensure all executors have read permissions\n"
                f"   3. Test access from each cluster node\n"
                f"   4. Alternative: copy file to HDFS for distributed access"
            )
        return str(file_path)  # Direct path for shared mounts
    else:
        return f"file://{str(file_path)}"  # Local file URI scheme
