<?php
namespace SabaiApps\Directories\Component\System\Widget;

use SabaiApps\Directories\Application;

/**
 * AbstractWidget provides a base class for system widgets.
 * Implements caching, settings, and content rendering logic.
 */
abstract class AbstractWidget implements IWidget {

	protected $_application, $_name, $_info, $_cacheable = true;

	/**
	 * Constructor.
	 *
	 * @param Application $application
	 * @param string      $name
	 */
	public function __construct( Application $application, $name ) {
		$this->_application = $application;
		$this->_name        = $name;
	}

	/**
	 * Returns widget information as an array, or a specific key if provided.
	 *
	 * @param string|null $key
	 * @return mixed
	 */
	public function systemWidgetInfo( $key = null ) {
		if ( ! isset( $this->_info ) ) {
			$this->_info = (array) $this->_systemWidgetInfo();
		}

		return isset( $key ) ? ( isset( $this->_info[ $key ] ) ? $this->_info[ $key ] : null ) : $this->_info;
	}

	/**
	 * Returns widget information array.
	 *
	 * @return array
	 */
	abstract protected function _systemWidgetInfo();

	/**
	 * Returns the settings form array for the widget.
	 *
	 * @param array $settings
	 * @return array
	 */
	public function systemWidgetSettings( array $settings ) {
		$form = array();
		if ( $this->_cacheable ) {
			$form['no_cache'] = array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Do not cache output', 'directories-pro' ),
				'#default_value' => false,
				'#weight'        => 99,
			);
		}
		if ( $widget_settings = $this->_getWidgetSettings( $settings ) ) {
			$form += $widget_settings;
		}
		return $this->_application->Filter( 'system_widget_settings_form', $form, array( $this->_name, $settings ) );
	}

	/**
	 * Returns the content array for the widget, using cache if enabled.
	 *
	 * @param array $settings
	 * @return array|null
	 */
	public function systemWidgetContent( array $settings ) {
		if ( ! $this->_cacheable
			|| ! empty( $settings['no_cache'] )
		) {
			$ret = $this->_getWidgetContent( $settings );
		} else {
			if ( ! $cache_id = $this->_getCacheId( $settings ) ) {
				return;
			}

			if ( false === $ret = $this->_application->getPlatform()->getCache( $cache_id, 'content' ) ) {
				$ret = $this->_getWidgetContent( $settings );
				$this->_application->getPlatform()->setCache( $ret, $cache_id, 3600, 'content' );
			}
		}
		if ( empty( $ret ) ) {
			return;
		}

		return array(
			'content' => $this->_application->Filter( 'system_widget_content', $ret, array( $this->_name, $settings ) ),
			'link'    => $this->_getWidgetLink( $settings ),
			'class'   => $this->_getWidgetClass( $settings ),
		);
	}

	/**
	 * Called when widget settings are saved, clears cache if needed.
	 *
	 * @param array $settings
	 * @param array $oldSettings
	 */
	public function systemWidgetOnSettingsSaved( array $settings, array $oldSettings ) {
		if ( ! $this->_cacheable ) {
			return;
		}

		$this->_application->getPlatform()->deleteCache( $this->_getCacheId( $oldSettings ), 'content' );
	}

	/**
	 * Returns the cache ID for the widget based on settings and language.
	 *
	 * @param array $settings
	 * @return string
	 */
	protected function _getCacheId( array $settings ) {
		$id = 'system_widget_' . $this->_name . '_' . md5( serialize( $settings ) );
		if ( $lang = $this->_application->getPlatform()->getCurrentLanguage() ) {
			$id .= '_' . $lang;
		}
		return $id;
	}

	/**
	 * Returns the widget link for the widget (optional).
	 *
	 * @param array $settings
	 * @return string|null
	 */
	protected function _getWidgetLink( array $settings ) {}

	/**
	 * Returns the CSS class for the widget (optional).
	 *
	 * @param array $settings
	 * @return string|null
	 */
	protected function _getWidgetClass( array $settings ) {}

	/**
	 * Returns the settings form array for the widget (to be implemented by subclass).
	 *
	 * @param array $settings
	 * @return array
	 */
	abstract protected function _getWidgetSettings( array $settings );

	/**
	 * Returns the content for the widget (to be implemented by subclass).
	 *
	 * @param array $settings
	 * @return mixed
	 */
	abstract protected function _getWidgetContent( array $settings );
}
