<?php
/**
 * Resolves Parkstatic storage paths under the WordPress uploads directory.
 *
 * @package Parkstatic
 */

declare(strict_types=1);

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

/**
 * Centralizes deploy artifact paths using wp_upload_dir().
 */
final class Parkstatic_Storage {

	private const SUBDIR               = 'parkstatic';
	private const MIGRATION_OPTION     = 'parkstatic_storage_migrated_v1';
	private const LEGACY_BASE_RELATIVE = 'parkstatic';

	/**
	 * @return array{basedir: string, baseurl: string, error: string|false}
	 */
	public static function uploads_dir(): array {
		return wp_upload_dir();
	}

	public static function base_dir(): string {
		$upload = self::uploads_dir();

		return trailingslashit( $upload['basedir'] ) . self::SUBDIR;
	}

	public static function static_dir(): string {
		return trailingslashit( self::base_dir() ) . 'static' . DIRECTORY_SEPARATOR;
	}

	public static function assets_dir(): string {
		return trailingslashit( self::base_dir() ) . 'assets' . DIRECTORY_SEPARATOR;
	}

	public static function releases_dir(): string {
		return trailingslashit( self::base_dir() ) . 'releases' . DIRECTORY_SEPARATOR;
	}

	public static function legacy_base_dir(): string {
		return trailingslashit( WP_CONTENT_DIR ) . self::LEGACY_BASE_RELATIVE;
	}

	/**
	 * Filesystem path to the static export's assets folder (no trailing slash).
	 */
	public static function static_assets_dir(): string {
		return untrailingslashit( self::static_dir() ) . '/assets';
	}

	/**
	 * Site-root-relative path used in root .htaccess rewrite targets.
	 */
	public static function static_assets_rewrite_target(): string {
		$assets_dir = wp_normalize_path( self::static_assets_dir() );
		$abspath    = wp_normalize_path( ABSPATH );

		if ( 0 === strpos( $assets_dir, $abspath ) ) {
			return trailingslashit( substr( $assets_dir, strlen( $abspath ) ) );
		}

		$upload = self::uploads_dir();
		$path   = wp_parse_url( $upload['baseurl'], PHP_URL_PATH );

		if ( ! is_string( $path ) || '' === $path ) {
			$path = '/wp-content/uploads';
		}

		return trailingslashit( $path ) . self::SUBDIR . '/static/assets/';
	}

	/**
	 * Normalizes URIs that point at stored static files into front-end paths.
	 */
	public static function normalize_storage_uri( string $uri ): string {
		$prefixes = array(
			'/wp-content/parkstatic/assets',
			'/wp-content/parkstatic/static',
			self::static_assets_uri_prefix(),
			self::static_export_uri_prefix(),
		);

		foreach ( $prefixes as $prefix ) {
			if ( '' === $prefix ) {
				continue;
			}

			if ( 0 === strpos( $uri, $prefix . '/' ) ) {
				if ( self::ends_with( $prefix, '/assets' ) ) {
					return '/assets' . substr( $uri, strlen( $prefix ) );
				}

				return substr( $uri, strlen( $prefix ) ) ?: '/';
			}

			if ( $uri === $prefix ) {
				return self::ends_with( $prefix, '/assets' ) ? '/assets' : '/';
			}
		}

		return $uri;
	}

	private static function static_export_uri_prefix(): string {
		$upload = self::uploads_dir();
		$path   = wp_parse_url( $upload['baseurl'], PHP_URL_PATH );

		if ( ! is_string( $path ) || '' === $path ) {
			$path = '/wp-content/uploads';
		}

		return trailingslashit( $path ) . self::SUBDIR . '/static';
	}

	private static function static_assets_uri_prefix(): string {
		return self::static_export_uri_prefix() . '/assets';
	}

	private static function ends_with( string $haystack, string $needle ): bool {
		if ( '' === $needle ) {
			return true;
		}

		return substr( $haystack, -strlen( $needle ) ) === $needle;
	}

	/**
	 * Moves deploy artifacts from the legacy wp-content/parkstatic tree.
	 */
	public static function maybe_migrate_legacy_storage(): void {
		if ( get_option( self::MIGRATION_OPTION, false ) ) {
			return;
		}

		$legacy = self::legacy_base_dir();
		$target = self::base_dir();

		if ( is_dir( $legacy ) && ! is_dir( $target ) ) {
			wp_mkdir_p( dirname( $target ) );

			// phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename
			if ( ! @rename( $legacy, $target ) ) {
				self::copy_directory_tree( $legacy, $target );
				self::remove_directory_tree( $legacy );
			}
		}

		update_option( self::MIGRATION_OPTION, true, false );

		if ( Parkstatic_Static_Site_Switcher::is_enabled() && Parkstatic_Static_Site_Switcher::write_htaccess_rules() ) {
			update_option( Parkstatic_Static_Site_Switcher::OPTION_HTACCESS_STORAGE_VERSION, Parkstatic_Static_Site_Switcher::HTACCESS_STORAGE_VERSION, false );
		}
	}

	private static function copy_directory_tree( string $source, string $destination ): void {
		wp_mkdir_p( $destination );

		$iterator = new RecursiveIteratorIterator(
			new RecursiveDirectoryIterator( $source, FilesystemIterator::SKIP_DOTS ),
			RecursiveIteratorIterator::SELF_FIRST
		);

		foreach ( $iterator as $item ) {
			/** @var SplFileInfo $item */
			$target_path = $destination . DIRECTORY_SEPARATOR . $iterator->getSubPathName();

			if ( $item->isDir() ) {
				wp_mkdir_p( $target_path );
				continue;
			}

			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_copy
			copy( $item->getPathname(), $target_path );
		}
	}

	public static function remove_directory_tree( string $directory ): void {
		if ( ! file_exists( $directory ) ) {
			return;
		}

		if ( is_file( $directory ) || is_link( $directory ) ) {
			wp_delete_file( $directory );
			return;
		}

		$iterator = new RecursiveIteratorIterator(
			new RecursiveDirectoryIterator( $directory, FilesystemIterator::SKIP_DOTS ),
			RecursiveIteratorIterator::CHILD_FIRST
		);

		foreach ( $iterator as $item ) {
			/** @var SplFileInfo $item */
			if ( $item->isDir() ) {
				// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir
				rmdir( $item->getPathname() );
			} else {
				wp_delete_file( $item->getPathname() );
			}
		}

		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir
		@rmdir( $directory );
	}
}
