<?php

/**
 * Base for admin pages.
 *
 * @package northmill-online-shared
 */
declare (strict_types=1);
namespace Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Admin\Pages;

use Closure;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Abstract_Shared_Base;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Helpers\Hook_Helpers;
use Northmill_Online_Shared_Checkout\Northmill_Online_Shared\Modules\Assets\Asset_Location_Enum;
defined('ABSPATH') || exit;
/**
 * Class Admin_Page
 */
abstract class Abstract_Admin_Page
{
    /**
     * Shared instance.
     *
     * @var Abstract_Shared_Base $shared
     */
    protected Abstract_Shared_Base $shared;
    /**
     * Key of the page collection containing this page.
     *
     * @var string $page_collection_key
     */
    public string $page_collection_key;
    /**
     * The ID of the settings page.
     *
     * @var string $page_id
     */
    public string $page_id;
    /**
     * The title of the settings page.
     * Can be a callable for translations to work.
     *
     * @var string|array|Closure $page_title
     */
    protected string|array|Closure $page_title;
    /**
     * The menu slug of the settings page.
     *
     * @var string $menu_slug
     */
    public string $menu_slug;
    /**
     * The menu title of the settings page.
     * Can be a callable for translations to work.
     *
     * @var string|array|Closure $menu_title
     */
    protected string|array|Closure $menu_title;
    /**
     * Whether this is the main page of the collection.
     *
     * @var bool $is_main_page
     */
    public bool $is_main_page;
    /**
     * Optional callback to get script localization data.
     *
     * @var array|Closure|null
     */
    private array|Closure|null $script_localization_callback;
    /**
     * Optional callback to get script dependency data.
     *
     * @var array|Closure|null
     */
    private array|Closure|null $script_dependencies_callback;
    /**
     * Initialize the class and set its properties.
     *
     * @param string               $page_collection_key          Collection key.
     * @param string               $page_id                      The ID of the settings page.
     * @param string|array|Closure $page_title                   The title of the settings page.
     * @param string|array|Closure $page_menu_title              The menu title of the settings page.
     * @param bool                 $is_main_page                 Whether this is the main page of the collection.
     * @param array|Closure|null   $script_localization_callback Optional callback to get script localization data.
     * @param array|Closure|null   $script_dependencies_callback Optional callback to get script dependency data.
     */
    public function __construct(string $page_collection_key, string $page_id, string|array|Closure $page_title, string|array|Closure $page_menu_title = '', bool $is_main_page = \false, array|Closure|null $script_localization_callback = null, array|Closure|null $script_dependencies_callback = null)
    {
        $this->shared = Abstract_Shared_Base::base_instance();
        $this->page_collection_key = $page_collection_key;
        $this->page_id = $page_id;
        $this->page_title = $page_title;
        $this->menu_slug = $this->shared->package_info->get_service_name_underscored() . '_' . $page_id;
        $this->menu_title = !empty($page_menu_title) ? $page_menu_title : $page_title;
        $this->is_main_page = $is_main_page;
        $this->script_localization_callback = $script_localization_callback;
        $this->script_dependencies_callback = $script_dependencies_callback;
        $this->register_ajax_actions();
        $this->shared->assets->enquer->register_script($this->page_id, Asset_Location_Enum::ADMIN, $this->get_script_dependencies(), array($this, 'get_script_localization'), array($this, 'is_this_admin_page'));
        $this->shared->assets->enquer->register_style($this->page_id, Asset_Location_Enum::ADMIN, $this->get_style_dependencies(), array($this, 'is_this_admin_page'));
        add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_styles'));
        add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
        $option = self::get_settings_id();
        add_filter("pre_update_option_{$option}", array($this, 'admin_page_pre_update_option'));
        add_action("update_option_{$option}", array($this, 'admin_page_updated_option'), 10, 3);
        $this->setup_page();
    }
    /**
     * Tells whether this page should be shown in the admin menu.
     * If this is for a main page, any submenu pages will not be shown either.
     *
     * @return bool
     */
    public function show_in_menu(): bool
    {
        return Hook_Helpers::apply_scoped_filters('northmill_online_shared_admin_page_show_in_menu_' . $this->page_id, \true);
    }
    /**
     * Get page settings id.
     *
     * @return string
     */
    public static function get_settings_id(): string
    {
        return Abstract_Shared_Base::base_instance()->package_info->get_service_name() . '-settings';
    }
    /**
     * Render the settings page.
     */
    public function render_settings_page(): void
    {
        $this->render_notices();
        Abstract_Shared_Base::base_instance()->template_loader->get_admin_template($this->page_id, $this->get_page_params());
    }
    /**
     * Render notices for admin page.
     */
    protected function render_notices()
    {
    }
    /**
     * Get page params.
     *
     * @return array
     */
    public function get_page_params(): array
    {
        return array();
    }
    /**
     * Checks if the current page is this admin page.
     *
     * @return bool
     */
    public function is_this_admin_page(): bool
    {
        if (!function_exists('get_current_screen')) {
            return \false;
        }
        $screen = get_current_screen();
        if (is_null($screen)) {
            return \false;
        }
        // phpcs:disable WordPress.PHP.YodaConditions.NotYoda
        if ($screen->id === 'toplevel_page_' . $this->menu_slug || $screen->id === Abstract_Shared_Base::base_instance()->package_info->get_service_name() . '_page_' . $this->menu_slug || $screen->id === 'wp-' . Abstract_Shared_Base::base_instance()->package_info->get_service_name() . '_page_' . $this->menu_slug) {
            return \true;
        }
        // phpcs:enable
        return \false;
    }
    /**
     * Enqueue styles for admin page.
     * Hooked to wp_enqueue_scripts.
     */
    public function admin_enqueue_styles(): void
    {
    }
    /**
     * Get style dependencies.
     *
     * @return array
     */
    public function get_style_dependencies(): array
    {
        return array();
    }
    /**
     * Enqueue scripts for admin page.
     * Hooked to wp_enqueue_scripts.
     */
    public function admin_enqueue_scripts(): void
    {
    }
    /**
     * Get script dependencies.
     *
     * @return array
     */
    private function get_script_dependencies(): array
    {
        $dependencies = array('jquery');
        if (is_callable($this->script_dependencies_callback)) {
            $dependencies = array_merge($dependencies, call_user_func($this->script_dependencies_callback));
        }
        $dependencies = array_merge($dependencies, $this->get_page_script_dependencies());
        $dependencies = array_unique($dependencies);
        return Hook_Helpers::apply_scoped_filters('northmill_online_shared_admin_page_script_dependencies_' . $this->page_id, $dependencies);
    }
    /**
     * Get page specific script dependencies.
     *
     * @return string[]
     */
    protected function get_page_script_dependencies(): array
    {
        return array();
    }
    /**
     * Get script localization.
     *
     * @param bool $is_shared Whether the asset is read from Shared.
     *
     * @return array
     */
    public function get_script_localization(bool $is_shared): array
    {
        $localization = array('settings_id' => self::get_settings_id());
        $localization['l10n'] = array();
        if (is_callable($this->script_localization_callback)) {
            $localization = call_user_func($this->script_localization_callback, $is_shared);
        }
        return Hook_Helpers::apply_scoped_filters('northmill_online_shared_admin_page_script_localization_' . $this->page_id, $localization, $is_shared);
    }
    /**
     * Handle updated options for page.
     *
     * @param mixed $posted_options Posted options, including all settings on the option page.
     *
     * @return array
     */
    final public function admin_page_pre_update_option(mixed $posted_options): array
    {
        return $this->pre_update_option($posted_options);
    }
    /**
     * Hooked to pre_update_option_{$option} filter.
     *
     * @param array $posted_options Posted options, including all settings on the option page.
     *
     * @return array
     */
    protected function pre_update_option(array $posted_options): array
    {
        return $posted_options;
    }
    /**
     * Handle updated options for page.
     *
     * @param mixed $old_value   Old value.
     * @param mixed $new_value   New value.
     *
     * @return void
     */
    final public function admin_page_updated_option(mixed $old_value, mixed $new_value): void
    {
        if (!isset($old_value[self::get_settings_id()]) || !is_array($old_value[self::get_settings_id()]) || !isset($new_value[self::get_settings_id()]) || !is_array($new_value[self::get_settings_id()])) {
            return;
        }
        $this->updated_options($old_value[self::get_settings_id()], $new_value[self::get_settings_id()]);
    }
    /**
     * Handle updated options for page. This is only called if the option is updated.
     *
     * @param array $old_options Old options.
     * @param array $new_options New options.
     *
     * @return void
     */
    protected function updated_options(array $old_options, array $new_options): void
    {
    }
    /**
     * Register ajax actions.
     */
    public function register_ajax_actions(): void
    {
        Hook_Helpers::do_scoped_action('northmill_online_shared_admin_page_ajax_' . $this->page_id);
    }
    /**
     *
     * Set up other aspects of the page.
     *
     * @return void
     */
    public function setup_page()
    {
    }
    /**
     * Get page menu title.
     */
    public function get_menu_title(): string
    {
        if (is_callable($this->menu_title)) {
            return call_user_func($this->menu_title);
        } elseif (!is_string($this->menu_title)) {
            return '';
        }
        return $this->menu_title;
    }
    /**
     * Get page title.
     */
    public function get_page_title(): array|Closure|string
    {
        if (is_callable($this->page_title)) {
            return call_user_func($this->page_title);
        } elseif (!is_string($this->page_title)) {
            return '';
        }
        return $this->page_title;
    }
}
