<?php
declare(strict_types=1);


namespace ProRank\SEO\Core;

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


/**
 * Filesystem helper wrappers for WordPress-compatible operations.
 */


class FilesystemHelper {
    /**
     * Get the WP_Filesystem instance, if available.
     *
     * @return \WP_Filesystem_Base|null
     */
    public static function get_filesystem(): ?\WP_Filesystem_Base {
        global $wp_filesystem;

        if ( $wp_filesystem instanceof \WP_Filesystem_Base ) {
            return $wp_filesystem;
        }

        if ( ! function_exists( 'WP_Filesystem' ) ) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }

        try {
            if ( WP_Filesystem() && $wp_filesystem instanceof \WP_Filesystem_Base ) {
                return $wp_filesystem;
            }
        } catch ( \Throwable $e ) {
            return null;
        }

        return null;
    }

    /**
     * Delete a file using WP_Filesystem or wp_delete_file().
     */
    public static function delete_file( string $path ): bool {
        if ( $path === '' ) {
            return false;
        }

        if ( function_exists( 'wp_delete_file' ) ) {
            $deleted = wp_delete_file( $path );
            if ( is_string( $deleted ) || true === $deleted ) {
                return true;
            }
        }

        $filesystem = self::get_filesystem();
        if ( $filesystem ) {
            try {
                return (bool) $filesystem->delete( $path, false, 'f' );
            } catch ( \Throwable $e ) {
                return false;
            }
        }

        return false;
    }

    /**
     * Remove a directory using WP_Filesystem.
     */
    public static function delete_dir( string $path, bool $recursive = true ): bool {
        if ( $path === '' ) {
            return false;
        }

        if ( ! is_dir( $path ) ) {
            return true;
        }

        if ( self::delete_dir_native( $path, $recursive ) ) {
            return true;
        }

        $filesystem = self::get_filesystem();
        if ( $filesystem ) {
            try {
                return (bool) $filesystem->delete( $path, $recursive, 'd' );
            } catch ( \Throwable $e ) {
                return false;
            }
        }

        return false;
    }

    /**
     * Move or rename a file using WP_Filesystem.
     */
    public static function move( string $from, string $to, bool $overwrite = true ): bool {
        if ( ! file_exists( $from ) ) {
            return false;
        }

        if ( ! $overwrite && file_exists( $to ) ) {
            return false;
        }

        $filesystem = self::get_filesystem();
        if ( $filesystem ) {
            try {
                if ( (bool) $filesystem->move( $from, $to, $overwrite ) ) {
                    return true;
                }
            } catch ( \Throwable $e ) {
                // Fall back to copy/unlink below.
            }
        }

        if ( ! @copy( $from, $to ) ) {
            return false;
        }

        return self::delete_file( $from );
    }

    /**
     * Output a file's contents safely.
     */
    public static function output_file( string $path ): bool {
        $contents = self::get_contents( $path );

        if ( false === $contents ) {
            return false;
        }

        echo $contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

        return true;
    }

    /**
     * Read a file using native filesystem access or WP_Filesystem.
     *
     * @return string|false
     */
    public static function get_contents( string $path ) {
        if ( $path === '' ) {
            return false;
        }

        if ( file_exists( $path ) ) {
            $contents = @file_get_contents( $path );
            if ( false !== $contents ) {
                return $contents;
            }
        }

        $filesystem = self::get_filesystem();
        if ( $filesystem ) {
            try {
                return $filesystem->get_contents( $path );
            } catch ( \Throwable $e ) {
                return false;
            }
        }

        return false;
    }

    /**
     * Write a file using WP_Filesystem when available, or native file access.
     */
    public static function put_contents( string $path, string $contents, int $chmod = 0644 ): bool {
        if ( $path === '' ) {
            return false;
        }

        $dir = dirname( $path );
        if ( $dir && ! is_dir( $dir ) && ! wp_mkdir_p( $dir ) ) {
            return false;
        }

        $filesystem = self::get_filesystem();
        if ( $filesystem ) {
            try {
                if ( $filesystem->put_contents( $path, $contents, $chmod ) ) {
                    return true;
                }
            } catch ( \Throwable $e ) {
                // Fall back to native write below.
            }
        }

        return false !== @file_put_contents( $path, $contents, LOCK_EX );
    }

    /**
     * Delete directories with native filesystem operations first.
     */
    private static function delete_dir_native( string $path, bool $recursive ): bool {
        if ( ! is_dir( $path ) ) {
            return true;
        }

        $entries = scandir( $path );
        if ( ! is_array( $entries ) ) {
            return false;
        }

        $entries = array_diff( $entries, [ '.', '..' ] );
        if ( ! $recursive && ! empty( $entries ) ) {
            return false;
        }

        foreach ( $entries as $entry ) {
            $child = rtrim( $path, '/\\' ) . DIRECTORY_SEPARATOR . $entry;
            if ( is_dir( $child ) && ! is_link( $child ) ) {
                if ( ! self::delete_dir_native( $child, true ) ) {
                    return false;
                }
            } elseif ( file_exists( $child ) && ! self::delete_file( $child ) ) {
                return false;
            }
        }

        $filesystem = self::get_filesystem();
        if ( ! $filesystem ) {
            return false;
        }

        try {
            return (bool) $filesystem->delete( $path, false, 'd' );
        } catch ( \Throwable $e ) {
            return false;
        }
    }
}
