<?php

declare( strict_types=1 );

namespace DocketConnector\Common\Settings;

use DocketConnector\PluginData;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Abort if this file is called directly.
}

if ( ! class_exists( Main::class ) ) {
	/**
	 * Everything related to setting, getting, and sanitizing plugin settings/options.
	 */
	class Main {

		/**
		 * Use text domain with underscores as our options prefix.
		 *
		 * @var string
		 */
		private $prefix;

		/**
		 * The Common Choices instance.
		 *
		 * @var Choices
		 */
		public $choices;

		/**
		 * Initialize the class and set its properties.
		 */
		public function __construct() {
			$this->choices = new Choices();
		}

		/**
		 * Get the option prefix.
		 *
		 * @see get_prefixed_option_key()
		 *
		 * @return string
		 */
		public function get_option_prefix(): string {
			// Just a way to identify where the prefix ends and the unique key starts.
			$delimiter = '__';

			if ( empty( $this->prefix ) ) {
				$this->prefix = PluginData::plugin_text_domain_underscores();
			}

			return $this->prefix . $delimiter;
		}

		/**
		 * Get the full option name, consistently prefixed, in a format that will work as a JavaScript object
		 * key (which is why hyphens get converted to underscores).
		 *
		 * @param string $key
		 *
		 * @return string
		 */
		public function get_prefixed_option_key( string $key ): string {
			$key = sanitize_key( $this->get_option_prefix() . $key );

			return str_replace( '-', '_', $key );
		}

		/**
		 * The translatable "Settings" text.
		 *
		 * @return string
		 */
		public function get_settings_word(): string {
			return esc_html__( 'Settings', 'docket-connector' );
		}

		/**
		 * The translatable "Docket Connector Settings" text.
		 *
		 * @return string
		 */
		public function get_settings_title(): string {
			return sprintf(
			// Translators: 1: plugin display name, 2: settings word
				esc_html_x(
					'%1$s %2$s',
					'settings title',
					'docket-connector'
				),
				PluginData::get_plugin_display_name(),
				$this->get_settings_word()
			);
		}

		/**
		 * Get a single option from the database, as a string, with an optional fallback value.
		 *
		 * @param string $key
		 * @param string $default
		 *
		 * @return string
		 */
		public function get_option_as_string( string $key, string $default = '' ): string {
			$result = $this->get_option( $key, $default );

			return $result;
		}

		/**
		 * Get the raw value of a single option from the database with an optional fallback value.
		 *
		 * @param string $key
		 * @param mixed  $default
		 *
		 * @return mixed
		 */
		public function get_option( string $key, $default = '' ) {
			$all_options = $this->get_all_options();

			// Cannot use empty() because an unchecked checkbox is boolean false, for example.
			if ( isset( $all_options[ $key ] ) ) {
				return $all_options[ $key ];
			} else {
				return $default;
			}
		}

		/**
		 * Get all of the saved options from the database.
		 *
		 * @return array
		 */
		public function get_all_options(): array {
			$plugin_options = get_option( PluginData::plugin_text_domain_underscores() );

			if ( ! empty( $plugin_options ) ) {
				return (array) $plugin_options;
			} else {
				return [];
			}
		}

		/**
		 * Get a single option from the database as an array with an optional fallback value.
		 *
		 * @todo Is array_keys() really what we want here?
		 *
		 * @param string $key
		 * @param mixed  $default
		 *
		 * @return array
		 */
		public function get_option_as_array( string $key, $default = '' ): array {
			$result = $this->get_option( $key, $default );

			if ( is_string( $result ) ) {
				$result = json_decode( $result, true );
			}

			$result = (array) $result;

			$result = array_keys( $result );

			return $result;
		}

		/**
		 * Delete all of the saved options from the database.
		 *
		 * @see delete_option()
		 *
		 * @return bool
		 */
		public function delete_all_options(): bool {
			return delete_option( PluginData::plugin_text_domain_underscores() );
		}

		/**
		 * Get all the option keys with this plugin's prefix.
		 *
		 * @param bool $only_if_show_in_rest Whether or not to exclude if 'show_in_rest' is false.
		 *
		 * @return array
		 */
		public function get_all_prefixed_options( bool $only_if_show_in_rest = true ): array {
			$prefix = $this->get_option_prefix();

			$all_settings = get_registered_settings();

			$result = [];

			foreach ( $all_settings as $key => $value ) {
				if ( 0 === strpos( $key, $prefix ) ) {
					if (
						$only_if_show_in_rest
						&& empty( $all_settings[ $key ]['show_in_rest'] )
					) {
						continue;
					}

					$result[] = $key; // we only want the option keys, not all their arguments
				}
			}

			return $result;
		}

	}
}
