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

use SabaiApps\Directories\Component\Entity\Type\IEntity;
use SabaiApps\Directories\Component\Field\IField;
use SabaiApps\Directories\Component\Field\Query;
use SabaiApps\Directories\Component\Entity\Model\Bundle;

class DateRangeType extends AbstractType implements ISortable, IOpenGraph, IHumanReadable, ISchemable, ICopiable, IConditionable, IQueryable, IDateRange {

	use QueryableRangeTrait, ConditionableRangeTrait {
		fieldConditionableInfo as traitFieldConditionableInfo;
	}

	protected function _fieldTypeInfo() {
		return array(
			'label'            => __( 'Date Range', 'directories-pro' ),
			'default_settings' => array(
				'date_range_enable' => false,
				'date_range'        => null,
			),
			'icon'             => 'fas fa-calendar-week',
			'schema_type'      => 'range',
		);
	}

	public function fieldTypeSettingsForm( $fieldType, Bundle $bundle, array $settings, array $parents = array(), array $rootParents = array() ) {
		return array(
			'date_range_enable' => array(
				'#type'          => 'checkbox',
				'#title'         => __( 'Restrict dates', 'directories-pro' ),
				'#default_value' => ! empty( $settings['date_range_enable'] ),
				'#states'        => array(
					'visible' => array(
						sprintf( 'input[name="%s[month_only]"]', $this->_application->Form_Form_fieldName( $parents ) ) => array(
							'type'  => 'checked',
							'value' => false,
						),
					),
				),
			),
			'date_range'        => array(
				'#type'          => 'daterangepicker',
				'#default_value' => is_array( $settings['date_range'] ) ? $settings['date_range'] : null,
				'#states'        => array(
					'visible' => array(
						sprintf( 'input[name="%s[month_only]"]', $this->_application->Form_Form_fieldName( $parents ) ) => array(
							'type'  => 'checked',
							'value' => false,
						),
						sprintf( 'input[name="%s[date_range_enable]"]', $this->_application->Form_Form_fieldName( $parents ) ) => array(
							'type'  => 'checked',
							'value' => true,
						),
					),
				),
			),
		);
	}

	public function fieldTypeOnSaveValues( IField $field, array $values, ?array $currentValues = null, array &$extraArgs = array() ) {
		$ret = array();
		foreach ( $values as $weight => $value ) {
			if ( ! is_array( $value )
				|| empty( $value[0] )
				|| ( ! is_numeric( $value[0] ) && ( ! $value[0] = $this->_application->System_Date_strToTime( $value[0] ) ) )
			) {
				continue;
			}

			if ( empty( $value[1] )
				|| ( ! is_numeric( $value[1] ) && ( ! $value[1] = $this->_application->System_Date_strToTime( $value[1] ) ) )
				|| $value[1] < $value[0]
			) {
				unset( $value[1] );
			}

			$ret[] = array(
				'min' => $value[0],
				'max' => $value[1],
			);
		}

		return $ret;
	}

	public function fieldTypeOnLoadValues( IField $field, array &$values, IEntity $entity, array $allValues ) {
		foreach ( array_keys( $values ) as $key ) {
			$values[ $key ] = array(
				'min' => (int) $values[ $key ]['min'],
				'max' => (int) $values[ $key ]['max'],
			);
		}
	}

	public function fieldSortableOptions( IField $field ) {
		return array(
			array(),
			array(
				'args'  => array( 'desc' ),
				'label' => __( '%s (desc)', 'directories-pro' ),
			),
		);
	}

	public function fieldSortableSort( Query $query, $fieldName, ?array $args = null ) {
		$query->sortByField( $fieldName, isset( $args ) && $args[0] === 'desc' ? 'DESC' : 'ASC', 'min' );
	}

	public function fieldOpenGraphProperties() {
		return array( 'books:release_date', 'music:release_date', 'video:release_date' );
	}

	public function fieldOpenGraphRenderProperty( IField $field, $property, IEntity $entity ) {
		if ( ! $value = $entity->getSingleFieldValue( $field->getFieldName(), 'min' ) ) {
			return;
		}

		return array( date( 'c', $value ) );
	}

	public function fieldConditionableInfo( IField $field, $isServerSide = false ) {
		if ( ! $isServerSide ) {
			return;
		}

		$info                = $this->traitFieldConditionableInfo( $field, $isServerSide );
		$info['']['tip']     = __( 'Enter a single date string or multiple date strings separated with a comma.', 'directories-pro' );
		$info['']['example'] = '12/31/2017,now';
		return $info;
	}

	protected function _getConditionableRuleValue( $value ) {
		return ( $value = $this->_application->System_Date_strToTime( $value ) ) ? $value : false;
	}

	public function fieldQueryableInfo( IField $field, $inAdmin = false ) {
		return array(
			'example' => '12/31/2017,now',
			'tip'     => __( 'Enter a single date string for exact match, two date strings separated with a comma for range search.', 'directories-pro' ),
		);
	}

	protected function _getQueryableQueryValue( $value ) {
		return ( $value = $this->_application->System_Date_strToTime( $value ) ) ? $value : false;
	}

	public function fieldSchemaProperties( IField $field ) {
		return array( 'datePublished', 'dateModified', 'dateCreated', 'startDate', 'endDate', 'datePosted', 'validThrough' );
	}

	public function fieldSchemaRenderProperty( IField $field, $property, IEntity $entity ) {
		if ( ! $value = $entity->getSingleFieldValue( $field->getFieldName() ) ) {
			return;
		}

		switch ( $property ) {
			case 'endDate':
				$ret = $value['max'];
				break;
			default:
				$ret = $value['min'];
		}
		return array( date( 'Y-m-d', $ret ) );
	}

	public function fieldCopyValues( IField $field, array $values, array &$allValue, $lang = null ) {
		return $values;
	}

	public function fieldDateRangeInfo( IField $field ) {
		return array(
			'start_column' => 'min',
			'end_column'   => 'max',
		);
	}

	public function fieldDateRange( IField $field, IEntity $entity ) {
		if ( ! $value = $entity->getSingleFieldValue( $field->getFieldName() ) ) {
			return;
		}

		return array( $value['min'], $value['max'] );
	}

	public function fieldHumanReadableText( IField $field, IEntity $entity, $separator = null, $key = null ) {
		if ( ! $values = $entity->getFieldValue( $field->getFieldName() ) ) {
			return '';
		}

		$ret = array();
		foreach ( $values as $value ) {
			$temp   = array();
			$temp[] = empty( $value['min'] ) ? '' : $this->_application->System_Date( $value['min'] );
			$temp[] = empty( $value['max'] ) ? '' : $this->_application->System_Date( $value['max'] );
			if ( empty( $temp ) ) {
				continue;
			}

			$ret[] = implode( ' - ', $temp );
		}
		return implode( isset( $separator ) ? $separator : PHP_EOL, $ret );
	}
}
