<?php

declare(strict_types=1);

namespace SecurWP\Includes;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * Resolve WordPress request paths across subdirectory installs and custom
 * content roots.
 */
class SitePathResolver {

    /**
     * Normalize a request path and optionally preserve a trailing slash.
     */
    public static function normalize_request_path( string $path, bool $trailing_slash = false ): string {
        $normalized = '/' . ltrim( trim( $path ), '/' );
        $normalized = preg_replace( '#/+#', '/', $normalized ) ?? $normalized;

        if ( $trailing_slash ) {
            return $normalized === '/' ? '/' : trailingslashit( $normalized );
        }

        return $normalized === '/' ? '/' : untrailingslashit( $normalized );
    }

    /**
     * Join two request-path fragments into a normalized absolute path.
     */
    public static function join_request_path( string $base_path, string $relative_path ): string {
        $base                    = self::normalize_request_path( $base_path, true );
        $preserve_trailing_slash = $relative_path === '' || substr( $relative_path, -1 ) === '/';

        return self::normalize_request_path( $base . ltrim( $relative_path, '/' ), $preserve_trailing_slash );
    }

    /**
     * Parse a URL into a normalized request path.
     */
    public static function get_public_path_from_url( string $url, bool $trailing_slash = false ): ?string {
        $path = wp_parse_url( $url, PHP_URL_PATH );
        if ( ! is_string( $path ) ) {
            return null;
        }

        return self::normalize_request_path( $path, $trailing_slash );
    }

    /**
     * Get the public request path to the WordPress install root.
     */
    public static function get_site_root_path(): string {
        return self::get_public_path_from_url( site_url( '/' ), true ) ?? '/';
    }

    /**
     * Resolve the public request path for a site-root file.
     */
    public static function get_site_root_file_path( string $filename ): string {
        return self::join_request_path( self::get_site_root_path(), $filename );
    }

    /**
     * Resolve the public request path for an admin-relative path.
     */
    public static function get_admin_public_path( string $relative = '' ): ?string {
        $admin_path = self::get_public_path_from_url( admin_url( '/' ), true );
        if ( $admin_path === null ) {
            return null;
        }

        return self::join_request_path( $admin_path, $relative );
    }

    /**
     * Resolve the public request path for a wp-includes-relative path.
     */
    public static function get_includes_public_path( string $relative = '' ): ?string {
        $includes_path = self::get_public_path_from_url( includes_url( '/' ), true );
        if ( $includes_path === null ) {
            return null;
        }

        return self::join_request_path( $includes_path, $relative );
    }

    /**
     * Resolve the public request path for the content root.
     */
    public static function get_content_public_path( string $relative = '' ): ?string {
        $content_path = self::get_public_path_from_url( content_url( '/' ), true );
        if ( $content_path === null ) {
            return null;
        }

        return self::join_request_path( $content_path, $relative );
    }

    /**
     * Resolve the public request path for a directory that may need PHP blocking.
     */
    public static function get_public_directory_path( string $dir ): ?string {
        switch ( $dir ) {
            case 'uploads':
                $url = (string) ( wp_upload_dir()['baseurl'] ?? '' );
                break;
            case 'plugins':
                $url = plugins_url( '/' );
                break;
            case 'mu-plugins':
                if ( defined( 'WPMU_PLUGIN_URL' ) && is_string( WPMU_PLUGIN_URL ) && WPMU_PLUGIN_URL !== '' ) {
                    $url = trailingslashit( WPMU_PLUGIN_URL );
                    break;
                }

                return self::get_content_public_path( 'mu-plugins/' );
            case 'themes':
                $url = trailingslashit( get_theme_root_uri() );
                break;
            default:
                return null;
        }

        return self::get_public_path_from_url( $url, true );
    }

    /**
     * Convert a site-local filesystem path to its public request path.
     */
    public static function get_public_path_from_local_path( string $path ): ?string {
        $path = trim( $path );
        if ( $path === '' ) {
            return null;
        }

        $normalized_path    = wp_normalize_path( $path );
        $normalized_abspath = trailingslashit( wp_normalize_path( ABSPATH ) );
        $normalized_content = trailingslashit( wp_normalize_path( WP_CONTENT_DIR ) );

        if ( str_starts_with( $normalized_path, $normalized_abspath ) ) {
            $relative = ltrim( substr( $normalized_path, strlen( $normalized_abspath ) ), '/' );
            return self::join_request_path( self::get_site_root_path(), $relative );
        }

        if ( str_starts_with( $normalized_path, $normalized_content ) ) {
            $content_root = self::get_content_public_path( '' );
            if ( $content_root === null ) {
                return null;
            }

            $relative = ltrim( substr( $normalized_path, strlen( $normalized_content ) ), '/' );
            return self::join_request_path( $content_root, $relative );
        }

        return null;
    }

    /**
     * Strip the site-root prefix from a public request path.
     */
    public static function get_site_relative_path( string $path ): string {
        $normalized = self::normalize_request_path( $path, false );
        $site_root  = self::get_site_root_path();

        if ( $site_root !== '/' && str_starts_with( $normalized, $site_root ) ) {
            return '/' . ltrim( substr( $normalized, strlen( $site_root ) ), '/' );
        }

        return $normalized;
    }
}
