<?php
namespace SabaiApps\Directories\Component\Form\Field;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Form\Form;

/**
 * AbstractField provides the base implementation for form fields.
 * Implements common logic for initialization, submission, cleanup, rendering, and error handling.
 */
abstract class AbstractField implements IField {

	// Reference to the application instance.
	protected $_application;

	protected static $_defaultBadgeColor;

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

	/**
	 * Initializes the field with settings and default values.
	 *
	 * @param string $name
	 * @param array  $data
	 * @param Form   $form
	 */
	public function formFieldInit( $name, array &$data, Form $form ) {}

	/**
	 * Handles field value processing and validation on form submit.
	 *
	 * @param mixed $value
	 * @param array $data
	 * @param Form  $form
	 */
	public function formFieldSubmit( &$value, array &$data, Form $form ) {}

	/**
	 * Cleans up field state after form submission.
	 *
	 * @param array $data
	 * @param Form  $form
	 */
	public function formFieldCleanup( array &$data, Form $form ) {}

	/**
	 * Determines if the field should be submitted based on the clicked button.
	 *
	 * @param array $data
	 * @param Form  $form
	 * @return bool
	 */
	public function formFieldIsSubmittable( array $data, Form $form ) {
		return ! isset( $data['#submit_for'] ) || $form->isClickedButton( $data['#submit_for'] );
	}

	/**
	 * Renders the field as HTML, including label, description, error, and input.
	 *
	 * @param string $html
	 * @param array  $data
	 * @param Form   $form
	 */
	protected function _render( $html, array &$data, Form $form ) {
		$error        = $form->hasError( $data['#name'] ) ? $form->getError( $data['#name'] ) : null;
		$output_error = empty( $data['#error_no_output'] ) && isset( $error ) && strlen( $error ) > 0;
		if ( ! empty( $data['#description_top'] ) ) {
			$description_top = $this->_getDescription( $data, true );
			$description     = $description_horizontal = '';
		} elseif ( ! empty( $data['#horizontal'] ) && ! empty( $data['#description_horizontal'] ) ) {
			$description            = $description_top = '';
			$description_horizontal = $this->_getDescription( $data, false );
		} else {
			$description     = ! $output_error ? $this->_getDescription( $data, false ) : '';
			$description_top = $description_horizontal = '';
		}
		if ( isset( $data['#title'] ) && strlen( $data['#title'] ) ) {
			$title = empty( $data['#title_no_escape'] ) ? $this->_application->H( $data['#title'] ) : $data['#title'];
			if ( ! empty( $data['#display_required'] ) ) {
				$title = '<label>' . $title . $form->getRequiredFieldSuffix() . '</label>';
			} else {
				$title = '<label>' . $title . '</label>';
			}
		} else {
			$title = '';
		}
		if ( empty( $data['#horizontal'] ) ) {
			// Render as a standard form group.
			$class  = strlen( $title ) || ! empty( $data['#group'] ) ? 'drts-form-group ' : '';
			$format = '<div class="' . $class . '%2$s%3$s" style="%5$s" data-form-field-name="%6$s"%4$s%7$s>
    %8$s
    <div class="drts-form-field-main">
        %9$s
        %10$s
        <div class="%1$sform-text drts-form-error %1$stext-danger">%11$s</div>
        %12$s
    </div>
</div>';
		} else {
			// Render as a horizontal form group.
			$label_width = is_int( $data['#horizontal'] ) && $data['#horizontal'] < 12 ? $data['#horizontal'] : 3;
			$format      = '<div class="drts-form-group %1$srow %2$s%3$s" style="%5$s" data-form-field-name="%6$s"%4$s%7$s>
        <div class="%1$scol-sm-' . $label_width . ' %1$scol-form-label %13$s">%8$s%14$s</div>
        <div class="%1$scol-sm-' . ( 12 - $label_width ) . ' drts-form-field-main">
            %9$s
            %10$s
            <div class="%1$sform-text drts-form-error %1$stext-danger">%11$s</div>
            %12$s
        </div>
    </div>';
		}
		$data['#html'][] = sprintf(
			$format,
			DRTS_BS_PREFIX,
			$this->_application->H( $data['#class'] ),
			isset( $error ) ? ' drts-form-has-error' : '',
			empty( $data['#id'] ) ? '' : ' id="' . $this->_application->H( $data['#id'] ) . '"',
			empty( $data['#hidden'] ) ? '' : 'display:none;',
			$this->_application->H( $data['#name'] ),
			empty( $data['#data'] ) ? '' : $this->_application->Attr( $data['#data'], null, 'data-' ),
			$title,
			$description_top,
			$html,
			$output_error ? $this->_application->Htmlize( $error, true ) : '',
			$description,
			! isset( $data['#horizontal_label_padding'] ) || $data['#horizontal_label_padding'] ? '' : DRTS_BS_PREFIX . 'pt-0',
			$description_horizontal
		);
	}

	/**
	 * Returns the description HTML for the field.
	 *
	 * @param array $data
	 * @param bool  $isTop
	 * @return string
	 */
	protected function _getDescription( array $data, $isTop = false ) {
		if ( ! isset( $data['#description'] ) || ! strlen( $data['#description'] ) ) {
			return '';
		}

		$class       = $isTop ? DRTS_BS_PREFIX . 'mt-0 ' . DRTS_BS_PREFIX . 'mb-3' : DRTS_BS_PREFIX . 'my-2';
		$description = empty( $data['#description_no_escape'] ) ? $this->_application->Htmlize(
			$data['#description'],
			array(
				'a' => array(
					'target' => true,
					'rel'    => true,
				),
			)
		) : $data['#description'];

		return '<div class="' . DRTS_BS_PREFIX . 'form-text drts-form-description ' . $class . '">' . $description . '</div>';
	}

	/**
	 * Returns the HTML for a standard input element.
	 *
	 * @param array  $data
	 * @param string $type
	 * @return string
	 */
	protected function _getInput( array $data, $type ) {
		return sprintf(
			'<input name="%s" type="%s" value="%s" class="%s%s"%s />',
			$this->_application->H( $data['#name'] ),
			$this->_application->H( $type ),
			isset( $data['#default_value'] ) ? $this->_application->H( $data['#default_value'] ) : '',
			! in_array( $type, array( 'hidden', 'file' ) ) ? DRTS_BS_PREFIX . 'form-control ' : '',
			isset( $data['#attributes']['class'] ) ? $this->_application->H( $data['#attributes']['class'] ) : '',
			$this->_application->Attr( $data['#attributes'], 'class' )
		);
	}

	/**
	 * Returns the HTML for a count badge.
	 *
	 * @param int         $count
	 * @param string|null $color
	 * @param string      $class
	 * @return string
	 */
	protected function _getCountBadge( $count, $color = null, $class = '' ) {
		if ( ! isset( $color ) ) {
			if ( ! isset( self::$_defaultBadgeColor ) ) {
				self::$_defaultBadgeColor = $this->_application->Filter( 'form_field_count_badge_default_color', 'light' );
			}
			$color = self::$_defaultBadgeColor;
		}
		return ' <span class="' . DRTS_BS_PREFIX . 'badge ' . DRTS_BS_PREFIX . 'rounded-pill ' . DRTS_BS_PREFIX . 'text-bg-' . $color . ' ' . $class . '">' . $this->_application->H( $count ) . '</span>';
	}
}
