<?php
/**
 * Field class.
 *
 * @package DokanKits\Admin\Dashboard\Components
 * @since   3.0.0
 */

namespace DokanKits\Admin\Dashboard\Components;

use DokanKits\Admin\Dashboard\Components\Fields\Button;
use DokanKits\Admin\Dashboard\Components\Fields\CardSelect;
use DokanKits\Admin\Dashboard\Components\Fields\Checkbox;
use DokanKits\Admin\Dashboard\Components\Fields\Currency;
use DokanKits\Admin\Dashboard\Components\Fields\MultiCheck;
use DokanKits\Admin\Dashboard\Components\Fields\MultiSelect;
use DokanKits\Admin\Dashboard\Components\Fields\Number;
use DokanKits\Admin\Dashboard\Components\Fields\Password;
use DokanKits\Admin\Dashboard\Components\Fields\Radio;
use DokanKits\Admin\Dashboard\Components\Fields\RadioBox;
use DokanKits\Admin\Dashboard\Components\Fields\Select;
use DokanKits\Admin\Dashboard\Components\Fields\Switcher;
use DokanKits\Admin\Dashboard\Components\Fields\Tel;
use DokanKits\Admin\Dashboard\Components\Fields\Text;
use DokanKits\Admin\Dashboard\Components\Fields\Toggle;


/**
 * Settings element Field.
 *
 * @since 3.0.0
 * @package DokanKits\Admin\Dashboard\Components
 */
class Field extends SettingsElement implements Fieldable {

	/**
	 * Is children Supported.
	 *
	 * @since 3.0.0
	 * @var bool $support_children Children support.
	 */
	protected bool $support_children = false;

	/**
	 * The Input Element Type.
	 *
	 * @since 3.0.0
	 * @var string $input_type The Input Element Type.
	 */
	protected string $input_type = 'text';

	/**
	 * The Settings Element Type.
	 *
	 * @since 3.0.0
	 * @var string $type Type Field.
	 */
	protected string $type = 'field';

	/**
	 * Map for the Input type.
	 *
	 * @since 3.0.0
	 * @var string[] $field_map Map for the Input type.
	 */
	protected array $field_map = array(
		'text'         => Text::class,
		'number'       => Number::class,
		'checkbox'     => Checkbox::class,
		'select'       => Select::class,
		'card-select'  => CardSelect::class,
		'multi-select' => MultiSelect::class,
		'radio'        => Radio::class,
		'tel'          => Tel::class,
		'password'     => Password::class,
		'radio_box'    => RadioBox::class,
		'switch'       => Switcher::class,
		'multicheck'   => MultiCheck::class,
		'currency'     => Currency::class,
		'toggle'       => Toggle::class,
		'button'       => Button::class,
	);

	/**
	 * Constructor.
	 *
	 * @since 3.0.0
	 * @param string $id ID of the input field.
	 * @param string $type Type of the input field.
	 */
	public function __construct( string $id, string $type = 'text' ) {
		/**
		 * Action before field initialization
		 *
		 * @since 3.0.0
		 * @param string $id Field ID.
		 * @param string $type Field type.
		 */
		do_action( 'dokan_kits_before_field_init', $id, $type );

		parent::__construct( $id );
		$this->input_type = $type;

		/**
		 * Action after field initialization
		 *
		 * @since 3.0.0
		 * @param Field $this Field instance.
		 * @param string $id Field ID.
		 * @param string $type Field type.
		 */
		do_action( 'dokan_kits_after_field_init', $this, $id, $type );
	}

	/**
	 * Get input field.
	 *
	 * @since 3.0.0
	 * @return SettingsElement
	 */
	public function get_input(): SettingsElement {
		/**
		 * Filter field map before getting input
		 *
		 * @since 3.0.0
		 * @param array $field_map Field type to class mapping.
		 * @param string $id Field ID.
		 * @param string $input_type Field type.
		 */
		$this->field_map = apply_filters( 'dokan_kits_field_map', $this->field_map, $this->get_id(), $this->input_type );

		return $this->input_map( $this->get_id(), $this->input_type );
	}

	/**
	 * Populate The Page Object.
	 *
	 * @since 3.0.0
	 * @return array
	 */
	public function populate(): array {
		/**
		 * Action before field population
		 *
		 * @since 3.0.0
		 * @param Field $this Field instance.
		 */
		do_action( 'dokan_kits_before_field_populate', $this );

		$data            = parent::populate();
		$data['variant'] = $this->input_type;

		$value = $this->get_value();

		/**
		 * Filter field value before escaping and populating
		 *
		 * @since 3.0.0
		 * @param mixed $value Field value.
		 * @param string $id Field ID.
		 * @param string $input_type Field type.
		 */
		$value = apply_filters( 'dokan_kits_field_value', $value, $this->get_id(), $this->input_type );

		$data['value'] = $this->escape_element( $value );

		/**
		 * Filter populated field data
		 *
		 * @since 3.0.0
		 * @param array $data Field data.
		 * @param Field $this Field instance.
		 */
		return apply_filters( 'dokan_kits_field_populated_data', $data, $this );
	}

	/**
	 * Map input type to field class
	 *
	 * @since 3.0.0
	 *
	 * @param string $id Field ID.
	 * @param string $type Field type.
	 *
	 * @return SettingsElement
	 */
	protected function input_map( string $id, string $type ): SettingsElement {
		/**
		 * Action before input mapping
		 *
		 * @since 3.0.0
		 * @param string $id Field ID.
		 * @param string $type Field type.
		 */
		do_action( 'dokan_kits_before_input_map', $id, $type );

		// Check if the type exists in the field map.
		if ( ! isset( $this->field_map[ $type ] ) ) {
			$type = 'text'; // Default to text field if type not found.
		}

		$class_name = $this->field_map[ $type ];

		/**
		 * Filter the field class name used for a specific field type
		 *
		 * @since 3.0.0
		 * @param string $class_name Field class name.
		 * @param string $id Field ID.
		 * @param string $type Field type.
		 */
		$class_name = apply_filters( 'dokan_kits_field_class_name', $class_name, $id, $type );

		$field = new $class_name( $id );

		/**
		 * Action after input mapping
		 *
		 * @since 3.0.0
		 *
		 * @param SettingsElement $field Created field instance.
		 * @param string          $id    Field ID.
		 * @param string          $type  Field type.
		 */
		do_action( 'dokan_kits_after_input_map', $field, $id, $type );

		return $field;
	}

	/**
	 * Data validation.
	 *
	 * @param mixed $data Data for validation.
	 *
	 * @return bool
	 */
	public function data_validation( $data ): bool {
		return isset( $data );
	}

	/**
	 * Sanitize data for storage.
	 *
	 * @param mixed $data Data for sanitization.
	 *
	 * @return array|float|string
	 */
	public function sanitize_element( $data ) {
		return wp_unslash( $data );
	}

	/**
	 * Escape data for display.
	 *
	 * @param mixed $data Data for display.
	 *
	 * @return mixed
	 */
	public function escape_element( $data ) {
		return $data;
	}

	/**
	 * Get the field default value
	 *
	 * @since  3.0.0
	 * @return mixed
	 */
	public function get_default() {
		return $this->default ?? '';
	}

	/**
	 * Set the field default value
	 *
	 * @since  3.0.0
	 * @param  mixed $default The default value.
	 * @return self
	 */
	public function set_default( $default ) {
		$this->default = $default;

		return $this;
	}
}
