<?php
/**
 * AG WP Plugin Install Manager — Installer View（1件用）。
 *
 * Plugin_Upgrader_Skin を拡張し、プラグイン1件の
 * インストール・更新時の画面出力を制御する。
 *
 * @package AG_WP_Plugin_Install_Manager
 */

// WordPress 外からの直接アクセスを禁止。
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// 依存クラスを読み込む。
if ( ! class_exists( 'Plugin_Upgrader_Skin' ) ) {
	require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
}

if ( ! class_exists( 'AG_WP_Installer_View' ) ) {

	/**
	 * プラグイン1件のインストール・更新時の画面出力を制御するクラス。
	 *
	 * @since 1.0.0
	 * @see Plugin_Upgrader_Skin
	 */
	class AG_WP_Installer_View extends Plugin_Upgrader_Skin {

		/**
		 * インストール完了後のリダイレクト先URL。
		 *
		 * @since 1.0.0
		 * @var string
		 */
		public $redirect_url = '';

		/**
		 * インストール対象のプラグインスラッグ。
		 *
		 * @since 1.0.0
		 * @var string
		 */
		public $plugin_slug = '';

		/**
		 * このスキンに対応するマネージャーの管理メニュースラッグ。
		 *
		 * @since 1.0.0
		 * @var string
		 */
		public $menu_slug = '';

		/**
		 * インストール完了時に表示するカスタムメッセージ。
		 *
		 * 空の場合は WordPress コアのデフォルトメッセージをそのまま表示する。
		 *
		 * @since 1.1.0
		 * @var string
		 */
		public $complete_message = '';

		/**
		 * コンストラクタ。
		 *
		 * @since 1.0.0
		 *
		 * @param array $args {
		 *     オプション。
		 *
		 *     @type string $redirect_url リダイレクト先URL。
		 *     @type string $plugin_slug  プラグインスラッグ。
		 *     @type string $url          アップグレード処理のURL（親クラス用）。
		 *     @type string $nonce        ノンス（親クラス用）。
		 * }
		 */
		public function __construct( $args = array() ) {
			$defaults = array(
				'redirect_url'     => '',
				'plugin_slug'      => '',
				'menu_slug'        => '',
				'complete_message' => '',
				'url'              => '',
				'nonce'            => '',
			);

			$args = wp_parse_args( $args, $defaults );

			$this->redirect_url     = $args['redirect_url'];
			$this->plugin_slug      = $args['plugin_slug'];
			$this->menu_slug        = $args['menu_slug'];
			$this->complete_message = $args['complete_message'];

			parent::__construct( $args );
		}

		/**
		 * WordPress コアの feedback() をオーバーライドし、完了メッセージを差し替える。
		 *
		 * $complete_message が設定されている場合、インストール完了を示す
		 * WordPress コアのフィードバックキー（plugin_install_success / process_success）を
		 * カスタムメッセージへ差し替える。
		 *
		 * @since 1.1.0
		 *
		 * @param string $string フィードバックキーまたはメッセージ文字列。
		 * @param mixed  ...$args 追加引数（親クラスへ委譲する際に使用）。
		 * @return void
		 */
		public function feedback( $string, ...$args ) {
			if ( ! empty( $this->complete_message )
				&& in_array( $string, array( 'plugin_install_success', 'process_success' ), true ) ) {
				echo '<p>' . esc_html( $this->complete_message ) . '</p>';
				return;
			}
			parent::feedback( $string, ...$args );
		}

		/**
		 * インストール開始前のヘッダーを出力する。
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function before() {
			// 処理前の表示が必要な場合はここに追加する。
		}

		/**
		 * インストール完了後の処理。
		 *
		 * エラーがなければリダイレクト先へ遷移する。
		 *
		 * @since 1.0.0
		 * @return void
		 */
		public function after() {
			// WordPress の Plugin_Installer_Skin::after() / Plugin_Upgrader_Skin::after() に倣い、
			// リダイレクトは行わずアクションリンクを feedback() で表示する。
			if ( ! empty( $this->redirect_url ) ) {
				$this->decrement_plugin_count();

				// 自動有効化の設定があれば有効化する。
				$this->maybe_activate_plugin();
			}

			$install_actions = array();

			if ( ! empty( $this->redirect_url ) && ! is_wp_error( $this->result ) ) {
				$install_actions['return_page'] = sprintf(
					'<a href="%s" target="_parent" class="button button-primary">%s</a>',
					esc_url( $this->redirect_url ),
					esc_html__( 'プラグイン管理画面に戻る', AG_WPIM_TEXTDOMAIN )
				);
			}

			if ( ! empty( $install_actions ) ) {
				$this->feedback( implode( ' ', $install_actions ) );
			}
		}

		/**
		 * エラーメッセージを出力する。
		 *
		 * @since 1.0.0
		 *
		 * @param string|WP_Error $errors エラーメッセージまたは WP_Error オブジェクト。
		 * @return void
		 */
		public function error( $errors ) {
			if ( is_string( $errors ) ) {
				echo '<p class="ag-wpim-error">' . esc_html( $errors ) . '</p>';
			} elseif ( $errors instanceof WP_Error ) {
				foreach ( $errors->get_error_messages() as $message ) {
					echo '<p class="ag-wpim-error">' . esc_html( $message ) . '</p>';
				}
			}
		}

		// =========================================================
		// 内部ヘルパー
		// =========================================================

		/**
		 * インストール完了後、必要であればプラグインを有効化する。
		 *
		 * @since 1.0.0
		 * @return void
		 */
		protected function maybe_activate_plugin() {
			if ( empty( $this->plugin_slug ) ) {
				return;
			}

			$manager = AG_WP_Plugin_Install_Manager::get_instance( $this->menu_slug );
			$plugins = $manager->get_plugins();

			if ( empty( $plugins[ $this->plugin_slug ]['force_activation'] ) ) {
				return;
			}

			// インストール済みファイルを特定して有効化する。
			if ( ! function_exists( 'get_plugins' ) ) {
				require_once ABSPATH . 'wp-admin/includes/plugin.php';
			}

			foreach ( get_plugins() as $plugin_file => $plugin_data ) {
				if ( 0 === strpos( $plugin_file, $this->plugin_slug . '/' ) ) {
					activate_plugin( $plugin_file );
					break;
				}
			}
		}

		/**
		 * セッションに保存しているインストール予定数をデクリメントする。
		 *
		 * バルク処理との連携用。
		 *
		 * @since 1.0.0
		 * @return void
		 */
		protected function decrement_plugin_count() {
			$key   = $this->get_install_count_transient_key();
			$count = get_transient( $key );
			if ( false !== $count && $count > 0 ) {
				set_transient( $key, $count - 1, HOUR_IN_SECONDS );
			}
		}

		/**
		 * インストール件数管理用のトランジェントキーを返す。
		 *
		 * menu_slug を含めることで、複数のテーマ・プラグインが
		 * このライブラリを同時に使用している場合でもキーが衝突しない。
		 *
		 * @since 1.0.0
		 * @return string
		 */
		protected function get_install_count_transient_key() {
			return 'ag_wpim_install_count_' . sanitize_key( $this->menu_slug );
		}
	}
}
