<?php
/**
 * Abstract class to be used as base for metabox controls.
 *
 * @package Neve\Admin\Metabox\Controls
 */

namespace Neve\Admin\Metabox\Controls;

/**
 * Class Control_Base
 *
 * @package Neve\Admin\Metabox\Controls
 */
abstract class Control_Base {

	/**
	 * Control id.
	 *
	 * @var string
	 */
	public $id = '';

	/**
	 * Control settings.
	 *
	 * @var array
	 */
	public $settings = array();

	/**
	 * Control type [MUST BE DEFINED]
	 *
	 * @var string
	 */
	public $type = '';

	/**
	 * Control Priority
	 *
	 * @var int
	 */
	public $priority = 10;

	/**
	 * Control_Base constructor.
	 *
	 * @param string $id       control id.
	 * @param array  $settings control settings.
	 */
	public function __construct( $id, $settings ) {
		if ( empty( $this->type ) ) {
			return;
		}
		$this->id       = $id;
		$this->settings = $settings;
		if ( isset( $settings['priority'] ) ) {
			$this->priority = $settings['priority'];
		}
	}

	/**
	 * Render function for the control.
	 */
	public function render( $post_id ) {
		if ( empty( $this->type ) ) {
			return;
		}
		if ( ! $this->should_render() ) {
			return;
		}

		$this->render_label();
		$this->render_content( $post_id );
		wp_nonce_field( 'neve_meta_box_nonce', 'neve_meta_box_process' );
	}

	/**
	 * Determine if a control should be visible or not.
	 *
	 * @return bool
	 */
	private function should_render() {
		if ( ! array_key_exists( 'active_callback', $this->settings ) ) {
			return true;
		}

		if ( empty( $this->settings['active_callback'] ) ) {
			return true;
		}

		$object = $this->settings['active_callback'][0];
		$method = $this->settings['active_callback'][1];
		if ( method_exists( $object, $method ) ) {
			return $object->$method();
		}

		return true;
	}

	/**
	 * Render control label.
	 *
	 * @return string
	 */
	protected function render_label() {
		$label = array_key_exists( 'label', $this->settings ) ? $this->settings['label'] : '';

		if ( empty( $label ) ) {
			return;
		}

		$control_label = '';

		$control_label .= '<p class="post-attributes-label-wrapper">';
		$control_label .= '<span class="post-attributes-label">' . esc_html( $label ) . '</span>';
		$control_label .= '</p>';

		echo wp_kses_post( $control_label );
	}

	/**
	 * Render control.
	 *
	 * @return void
	 */
	abstract public function render_content( $post_id );

	/**
	 * Save control data.
	 *
	 * @param string $post_id Post id.
	 *
	 * @return void
	 */
	final public function save( $post_id ) {
		if ( ! isset( $_POST['neve_meta_box_process'] ) ) {
			return;
		}
		if ( ! wp_verify_nonce( sanitize_key( $_POST['neve_meta_box_process'] ), 'neve_meta_box_nonce' ) ) {
			return;
		}
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}
		if ( ! current_user_can( 'edit_posts' ) ) {
			return;
		}
		if ( isset( $_POST[ $this->id ] ) ) {
			$value = $this->sanitize_value( wp_unslash( $_POST[ $this->id ] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			// Remove post meta on default.
			if ( $value === $this->settings['default'] ) {
				delete_post_meta( $post_id, $this->id );

				return;
			}
			// Update post meta on other values.
			update_post_meta( $post_id, $this->id, $value );

			return;
		} else {
			if ( $this->id === 'neve_meta_enable_content_width' ) {
				update_post_meta( $post_id, 'neve_meta_enable_content_width', 'off' );
			} else {
				delete_post_meta( $post_id, $this->id );
			}
			return;
		}
	}

	/**
	 * Sanitize the value.
	 *
	 * @param int|string $value the value to sanitize.
	 *
	 * @return int|string
	 */
	protected function sanitize_value( $value ) {
		switch ( $this->type ) {
			case 'radio':
				$allowed_values = $this->settings['choices'];
				if ( ! array_key_exists( $value, $allowed_values ) ) {
					return esc_html( $this->settings['default'] );
				}

				return sanitize_text_field( $value );
			case 'checkbox':
				$allowed_values = array( 'on', 'off' );
				if ( ! in_array( $value, $allowed_values, true ) ) {
					return esc_html( $this->settings['default'] );
				}

				return sanitize_text_field( $value );
			case 'range':
				return absint( $value );
			case 'input':
				return sanitize_text_field( $value );
			case 'separator':
			default:
				break;
		}

		return sanitize_text_field( $value );
	}

	/**
	 * Get the value.
	 *
	 * @param int $post_id the post id.
	 *
	 * @return mixed
	 */
	final protected function get_value( $post_id ) {
		$value = get_post_meta( $post_id, $this->id, true );

		return ! empty( $value ) ? $value : $this->settings['default'];
	}
}
