<?php

namespace CelerSearch\Utilities;

/**
 * WordPress Filesystem wrapper
 *
 * Provides a simple interface to WP_Filesystem for file operations.
 * Uses direct filesystem access method suitable for plugin operations
 * in the uploads directory.
 *
 * Usage:
 *   $fs = new Filesystem();
 *   if ( $fs->initialize() ) {
 *       $fs->put_contents( '/path/to/file.txt', 'content' );
 *   }
 */
class Filesystem {

	/**
	 * WP_Filesystem instance
	 *
	 * @var \WP_Filesystem_Base|null
	 */
	private ?\WP_Filesystem_Base $wp_filesystem = null;

	/**
	 * Whether initialization has been attempted
	 *
	 * @var bool
	 */
	private bool $initialized = false;

	/**
	 * Initialize the WordPress filesystem
	 *
	 * @return bool True if filesystem is ready, false on failure
	 */
	public function initialize(): bool {
		if ( $this->initialized ) {
			return $this->wp_filesystem !== null;
		}

		$this->initialized = true;

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

		// Initialize with direct method (no credentials needed for local files)
		$initialized = WP_Filesystem( false, false, true );

		if ( $initialized ) {
			global $wp_filesystem;
			$this->wp_filesystem = $wp_filesystem;
		}

		return $this->wp_filesystem !== null;
	}

	/**
	 * Write contents to a file
	 *
	 * @param string    $file     Path to the file.
	 * @param string    $contents File contents.
	 * @param int|false $mode     Optional. File mode. Default false (use default permissions).
	 *
	 * @return bool True on success, false on failure.
	 */
	public function put_contents( string $file, string $contents, $mode = false ): bool {
		if ( ! $this->initialize() ) {
			return false;
		}

		return $this->wp_filesystem->put_contents( $file, $contents, $mode );
	}

	/**
	 * Read contents from a file
	 *
	 * @param string $file Path to the file.
	 *
	 * @return string|false File contents on success, false on failure.
	 */
	public function get_contents( string $file ) {
		if ( ! $this->initialize() ) {
			return false;
		}

		return $this->wp_filesystem->get_contents( $file );
	}

	/**
	 * Check if a file or directory exists
	 *
	 * @param string $path Path to check.
	 *
	 * @return bool True if exists, false otherwise.
	 */
	public function exists( string $path ): bool {
		if ( ! $this->initialize() ) {
			return file_exists( $path );
		}

		return $this->wp_filesystem->exists( $path );
	}

	/**
	 * Check if a path is writable
	 *
	 * @param string $path Path to check.
	 *
	 * @return bool True if writable, false otherwise.
	 */
	public function is_writable( string $path ): bool {
		if ( ! $this->initialize() ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable
			return is_writable( $path );
		}

		return $this->wp_filesystem->is_writable( $path );
	}

	/**
	 * Create a directory
	 *
	 * @param string    $path  Path to create.
	 * @param int|false $chmod Optional. Directory permissions. Default false.
	 *
	 * @return bool True on success, false on failure.
	 */
	public function mkdir( string $path, $chmod = false ): bool {
		if ( ! $this->initialize() ) {
			return wp_mkdir_p( $path );
		}

		// WP_Filesystem mkdir doesn't create parent directories
		// Use wp_mkdir_p for recursive creation, then verify
		if ( ! wp_mkdir_p( $path ) ) {
			return false;
		}

		return $this->wp_filesystem->exists( $path );
	}

	/**
	 * Delete a file
	 *
	 * @param string $file Path to the file.
	 *
	 * @return bool True on success, false on failure.
	 */
	public function delete( string $file ): bool {
		if ( ! $this->initialize() ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
			return @unlink( $file );
		}

		return $this->wp_filesystem->delete( $file );
	}

	/**
	 * Rename/move a file
	 *
	 * @param string $source      Source path.
	 * @param string $destination Destination path.
	 *
	 * @return bool True on success, false on failure.
	 */
	public function move( string $source, string $destination ): bool {
		if ( ! $this->initialize() ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename
			return @rename( $source, $destination );
		}

		return $this->wp_filesystem->move( $source, $destination );
	}

	/**
	 * Get file size
	 *
	 * @param string $file Path to the file.
	 *
	 * @return int|false File size in bytes, or false on failure.
	 */
	public function size( string $file ) {
		if ( ! $this->initialize() ) {
			return @filesize( $file );
		}

		return $this->wp_filesystem->size( $file );
	}

	/**
	 * Append contents to a file
	 *
	 * Note: WP_Filesystem doesn't have a native append method,
	 * so we read existing content and write combined content.
	 * For high-frequency logging, consider using direct file operations.
	 *
	 * @param string $file     Path to the file.
	 * @param string $contents Content to append.
	 *
	 * @return bool True on success, false on failure.
	 */
	public function append( string $file, string $contents ): bool {
		if ( ! $this->initialize() ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
			return file_put_contents( $file, $contents, FILE_APPEND | LOCK_EX ) !== false;
		}

		$existing = '';
		if ( $this->wp_filesystem->exists( $file ) ) {
			$existing = $this->wp_filesystem->get_contents( $file );
			if ( $existing === false ) {
				$existing = '';
			}
		}

		return $this->wp_filesystem->put_contents( $file, $existing . $contents );
	}
}
