<?php
namespace R2_Offload;

defined( 'ABSPATH' ) || exit;

final class Installer {

	public const FLAG_OPTION = 'r2_offload_deps_state';

	public static function vendor_ready(): bool {
		return file_exists( R2_OFFLOAD_DIR . 'vendor/autoload.php' )
			&& class_exists( '\\Google\\Cloud\\Storage\\StorageClient' );
	}

	public static function state(): array {
		return wp_parse_args(
			(array) get_option( self::FLAG_OPTION, [] ),
			[ 'status' => 'missing', 'message' => '', 'ran_at' => '' ]
		);
	}

	private static function save_state( string $status, string $message ): void {
		update_option(
			self::FLAG_OPTION,
			[ 'status' => $status, 'message' => $message, 'ran_at' => current_time( 'mysql' ) ],
			false
		);
	}

	public static function install(): array {
		if ( self::vendor_ready() ) {
			self::save_state( 'ok', 'Already installed.' );
			return [ 'ok' => true, 'message' => 'Already installed.' ];
		}

		if ( ! self::exec_available() ) {
			$msg = 'PHP exec() disabled. Run `composer install` manually inside ' . R2_OFFLOAD_DIR;
			self::save_state( 'error', $msg );
			return [ 'ok' => false, 'message' => $msg ];
		}

		$composer = self::find_or_fetch_composer();
		if ( ! $composer ) {
			$msg = 'composer not found and composer.phar download failed.';
			self::save_state( 'error', $msg );
			return [ 'ok' => false, 'message' => $msg ];
		}

		@set_time_limit( 600 );
		$cwd = escapeshellarg( untrailingslashit( R2_OFFLOAD_DIR ) );
		$cmd = 'cd ' . $cwd . ' && '
			. ( str_ends_with( $composer, '.phar' ) ? 'php ' . escapeshellarg( $composer ) : escapeshellarg( $composer ) )
			. ' install --no-dev --no-interaction --prefer-dist --optimize-autoloader 2>&1';

		$out  = [];
		$code = 0;
		@exec( $cmd, $out, $code );

		if ( $code !== 0 || ! self::vendor_ready() ) {
			$msg = 'Composer install failed (exit ' . $code . ").\n" . implode( "\n", array_slice( $out, -30 ) );
			self::save_state( 'error', $msg );
			return [ 'ok' => false, 'message' => $msg ];
		}

		self::save_state( 'ok', 'Installed successfully.' );
		return [ 'ok' => true, 'message' => 'Installed successfully.' ];
	}

	private static function exec_available(): bool {
		if ( ! function_exists( 'exec' ) ) {
			return false;
		}
		$disabled = explode( ',', (string) ini_get( 'disable_functions' ) );
		$disabled = array_map( 'trim', $disabled );
		return ! in_array( 'exec', $disabled, true );
	}

	private static function find_or_fetch_composer(): ?string {
		foreach ( [ 'composer', '/usr/local/bin/composer', '/opt/homebrew/bin/composer' ] as $bin ) {
			$out  = [];
			$code = 0;
			@exec( escapeshellarg( $bin ) . ' --version 2>&1', $out, $code );
			if ( $code === 0 ) {
				return $bin;
			}
		}

		$target = R2_OFFLOAD_DIR . 'composer.phar';
		if ( file_exists( $target ) ) {
			return $target;
		}

		$res = wp_remote_get(
			'https://getcomposer.org/composer-stable.phar',
			[ 'timeout' => 120, 'stream' => true, 'filename' => $target ]
		);
		if ( is_wp_error( $res ) ) {
			return null;
		}
		$code = (int) wp_remote_retrieve_response_code( $res );
		if ( $code !== 200 || ! file_exists( $target ) || filesize( $target ) < 100000 ) {
			@unlink( $target );
			return null;
		}
		@chmod( $target, 0755 );
		return $target;
	}
}
