<?php
/**
 * Handle notices.
 *
 * @package northmill-online-shared
 */

declare(strict_types=1);

namespace Northmill_Online_Shared\Modules\Admin\Notices;

use Closure;
use Northmill_Online_Shared\Abstract_Shared_Base;
use Northmill_Online_Shared\Modules\Abstract_Module;
use Northmill_Online_Shared\Modules\Admin\Notices\Models\Notice_Model;
use Northmill_Online_Shared\Modules\Assets\Asset_Location_Enum;

defined( 'ABSPATH' ) || exit;

/**
 * Class Notice_Module
 */
class Notice_Module extends Abstract_Module {

	private const NOTICE_CLOSED_AJAX_KEY = 'closed_admin_notice';

	/**
	 * Set up the module.
	 */
	public function setup(): void {
		$this->shared->assets->enquer->register_script(
			'general/admin-notices',
			Asset_Location_Enum::ADMIN,
			array( 'jquery', 'ajax-script-shared' ),
			array( $this, 'script_localization' ),
			array( $this, 'has_notices' )
		);

		Abstract_Shared_Base::base_instance()->ajax->add_action(
			self::NOTICE_CLOSED_AJAX_KEY,
			array( $this, 'ajax_closed_notice' )
		);
	}

	/**
	 * Registered notices.
	 *
	 * @var Notice_Model[] $notices
	 */
	private array $notices = array();

	/**
	 * Register notice.
	 *
	 * @param string               $key         Key of the notice.
	 * @param Notice_Type_Enum     $type        Type of the notice.
	 * @param string|array|Closure $text        Text of the notice. Can be a callable to delay translation.
	 * @param bool                 $dismissible Whether the notice is dismissible.
	 * @param array|Closure|bool   $should_show Whether the notice should be shown.
	 * @param array                $args        Additional arguments to pass to wp_admin_notice().
	 *
	 * @used Northmill Sync
	 */
	public function register_notice(
		string $key,
		Notice_Type_Enum $type,
		string|array|Closure $text,
		bool $dismissible = true,
		array|Closure|bool $should_show = true,
		array $args = array()
	): void {
		$this->notices[ $key ] = new Notice_Model(
			$key,
			$type,
			$text,
			$dismissible,
			$should_show,
			$args
		);
	}

	/**
	 * Get notice.
	 *
	 * @param string $key Key of the notice.
	 *
	 * @return Notice_Model|null
	 *
	 * @used Northmill Sync
	 */
	public function get_notice( string $key ): ?Notice_Model {
		return $this->notices[ $key ] ?? null;
	}

	/**
	 * Get whether any notices are registered.
	 *
	 * @return bool
	 */
	public function has_notices(): bool {
		return ! empty( $this->notices );
	}

	/**
	 * Get script localization.
	 *
	 * @param bool $is_shared Whether the script being enqueued is in Shared.
	 *
	 * @return array
	 * @noinspection PhpUnusedParameterInspection
	 */
	public function script_localization( bool $is_shared ): array {
		return array(
			'closed_ajax' => Abstract_Shared_Base::base_instance()->ajax->get_action( self::NOTICE_CLOSED_AJAX_KEY )->get_data_for_js(),
		);
	}

	/**
	 * Ajax callback for closing a notice.
	 *
	 * @return void
	 */
	public function ajax_closed_notice(): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( 'Unauthorized', 403 );
		}

		// phpcs:ignore WordPress.Security.NonceVerification -- Nonce verification is done in the AJAX handler.
		$notice_key = $_POST['notice_key'];

		if ( ! array_key_exists( $notice_key, $this->notices ) ) {
			wp_send_json_error( 'Notice not found' );
		}

		$notice = $this->notices[ $notice_key ];

		$notice->set_closed();

		wp_send_json_success( 'Notice closed' );
	}
}
