<?php

namespace Limb_Chatbot\Includes\Data_Objects;

use Limb_Chatbot\Includes\Database_Strategies\WP_Options;
use Limb_Chatbot\Includes\Services\Helper;


/**
 * Class Setting
 *
 * Represents a setting stored in the WordPress options table, with JSON decoding support.
 *
 * @since 1.0.0
 */
class Setting extends Data_Object {

	/**
	 * Prefix for all setting keys.
	 *
	 * @since 1.0.0
	 */
	const SETTING_PREFIX = 'lbaic.';

	/**
	 * Allowed characters in the key (letters, numbers, dot, underscore, dash).
	 *
	 * @since 1.0.0
	 */
	const KEY_REGEXP = 'a-zA-Z0-9._-';

	/**
	 * WordPress options table.
	 *
	 * @since 1.0.0
	 */
	const TABLE_NAME = 'options';

	/**
	 * Postfix used for preview keys.
	 *
	 * @since 1.0.0
	 */
	const PREVIEW_POSTFIX = '.preview';

	/**
	 * Setting key.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	public string $key;

	/**
	 * Setting value, can be of any type.
	 *
	 * @var mixed
	 * @since 1.0.0
	 */
	public $value;

	/**
	 * Constructor.
	 *
	 * Decodes JSON values automatically.
	 *
	 * @param mixed|null $instance Optional initial data.
	 * @since 1.0.0
	 */
	public function __construct( $instance = null ) {
		if ( is_array( $instance ) && ! empty( $instance['value'] ) && $this->isJson( $instance['value'] ) ) {
			$instance['value'] = Helper::maybe_json_decode( $instance['value'] );
		}
		parent::__construct( $instance );
	}

	/**
	 * Returns the DB strategy instance for this class.
	 *
	 * @return WP_Options
	 * @since 1.0.0
	 */
	static function get_db_strategy(): WP_Options {
		return WP_Options::instance();
	}

	/**
	 * Gets the setting value.
	 *
	 * @return mixed
	 * @since 1.0.0
	 */
	public function get_value() {
		return $this->value;
	}

	/**
	 * Sets the setting value.
	 *
	 * @param mixed $value Value to set.
	 * @return void
	 * @since 1.0.0
	 */
	public function set_value( $value ): void {
		$this->value = $value;
	}

	/**
	 * Gets the setting key.
	 *
	 * @return string
	 * @since 1.0.0
	 */
	public function get_key(): string {
		return $this->key;
	}

	/**
	 * Sets the setting key.
	 *
	 * @param string $key Key to set.
	 * @return void
	 * @since 1.0.0
	 */
	public function set_key( $key ): void {
		$this->key = $key;
	}

	/**
	 * Sanitizes a given key, removing disallowed characters.
	 *
	 * @param string $key The key to sanitize.
	 * @return string|null Sanitized key or null if empty.
	 * @since 1.0.0
	 */
	public static function sanitize_key( $key ): ?string {
		return preg_replace( '/[^' . self::KEY_REGEXP . ']/', '', sanitize_text_field( $key ) );
	}

	/**
	 * Finds a setting by key, adding prefix if missing.
	 *
	 * @param string $id Setting key.
	 * @return static|null
	 * @since 1.0.0
	 */
	public static function find( $id ) {
		if ( ! str_starts_with( $id, self::SETTING_PREFIX ) ) {
			$id = self::SETTING_PREFIX . $id;
		}

		return parent::find( $id );
	}

	/**
	 * Checks if a setting exists.
	 *
	 * @param string $id Setting key.
	 * @return bool True if exists, false otherwise.
	 * @since 1.0.0
	 */
	public static function exists( $id ): bool {
		return self::get_db_strategy()->exists( $id );
	}
}