<?php
namespace SabaiApps\Directories\Component\Entity\FieldType;

use SabaiApps\Directories\Component\Field\Type\AbstractType;
use SabaiApps\Directories\Component\Entity\Type\IEntity;
use SabaiApps\Directories\Component\Entity\Model\Bundle;
use SabaiApps\Directories\Component\Field\IField;
use SabaiApps\Directories\Component\Field\Query;
use SabaiApps\Directories\Component\Field\Type\ISortable;
use SabaiApps\Directories\Component\Field\Type\IQueryable;
use SabaiApps\Directories\Component\Field\Type\IColumnable;
use SabaiApps\Directories\Component\Field\Type\IComparable;
use SabaiApps\Directories\Exception\IException;

class ChildCountFieldType extends AbstractType implements
	ISortable,
	IQueryable,
	IColumnable,
	IComparable {

	protected function _fieldTypeInfo() {
		return array(
			'label'     => __( 'Child Content Count', 'directories-pro' ),
			'creatable' => false,
		);
	}

	public function fieldTypeSchemaType( $type, $name ) {
		return 'entity_content_count';
	}

	public function fieldTypeOnSaveValues( IField $field, array $values, ?array $currentValues = null, array &$extraArgs = array() ) {
		$ret = array();
		foreach ( $values as $value ) {
			if ( ! is_array( $value ) ) {
				$ret[] = false; // delete
			} else {
				$ret[] = $value;
			}
		}
		return $ret;
	}

	public function fieldTypeOnLoadValues( IField $field, array &$values, IEntity $entity, array $allValues ) {
		$new_values = array();
		foreach ( $values as $value ) {
			// Index by child bundle name for easier access to counts
			$new_values[0][ $value['content_name'] ] = (int) $value['value'];
		}
		$values = $new_values;
	}

	public function fieldTypeIsModified( IField $field, $valueToSave, $currentLoadedValue ) {
		$current = $new = array();
		if ( ! empty( $currentLoadedValue[0] ) ) {
			foreach ( $currentLoadedValue[0] as $child_bundle_name => $value ) {
				$current[] = array(
					'value'        => $value,
					'content_name' => $child_bundle_name,
				);
			}
		}
		foreach ( $valueToSave as $value ) {
			$new[] = array(
				'value'        => (int) $value['value'],
				'content_name' => $value['content_name'],
			);
		}
		return $current !== $new;
	}

	public function fieldSortableOptions( IField $field ) {
		$ret = array();
		foreach ( $this->_getChildBundleNames( $field ) as $child_bundle_name ) {
			if ( ! $child_bundle = $this->_application->Entity_Bundle( $child_bundle_name ) ) {
				continue;
			}

			$ret[] = array(
				'label' => sprintf( _x( 'Most %s', 'sort option label', 'directories-pro' ), $child_bundle->getLabel() ),
				'args'  => array( $child_bundle->type ),
			);
			$ret[] = array(
				'label' => sprintf( _x( 'Least %s', 'sort option label', 'directories-pro' ), $child_bundle->getLabel() ),
				'args'  => array( $child_bundle->type, 'asc' ),
			);
		}

		return empty( $ret ) ? false : $ret;
	}

	public function fieldSortableSort( Query $query, $fieldName, ?array $args = null ) {
		if ( ! isset( $args[0] ) ) {
			return;
		}

		$query->startCriteriaGroup( 'OR' )
			->fieldIs( $fieldName, $args[0], 'content_name' )
			->fieldIsNull( $fieldName, 'content_name' ) // include those without any child bundle count
			->finishCriteriaGroup()
			->sortByField( $fieldName, isset( $args[1] ) && $args[1] === 'asc' ? 'ASC' : 'DESC', 'value', null, 0 );
	}

	public function fieldQueryableInfo( IField $field, $inAdmin = false ) {
		return array(
			'example' => 'directory_rev_rev,5',
			'tip'     => __( 'Enter a child content type name and up to two numbers separated with a comma for range search.', 'directories-pro' ),
		);
	}

	public function fieldQueryableQuery( Query $query, $fieldName, $paramStr, Bundle $bundle ) {
		$params = $this->_queryableParams( $paramStr );
		if ( ! empty( $params[1] ) || ! empty( $params[2] ) ) {
			$query->fieldIs( $fieldName, $params[0], 'content_name' );
			if ( ! empty( $params[1] ) ) {
				$query->fieldIsOrGreaterThan( $fieldName, $params[1] );
			}
			if ( ! empty( $params[2] ) ) {
				$query->fieldIsOrSmallerThan( $fieldName, $params[2] );
			}
		}
	}

	public function fieldColumnableInfo( IField $field ) {
		$ret = array();
		foreach ( $this->_getChildBundleNames( $field, false ) as $child_bundle_name ) {
			if ( ! $child_bundle = $this->_application->Entity_Bundle( $child_bundle_name ) ) {
				continue;
			}

			$ret[ $child_bundle->type ] = array(
				'label'       => $child_bundle->getLabel(),
				'table_join'  => array( 'content_name' => $child_bundle->type ),
				'table_alias' => $field->getFieldName() . '_' . $child_bundle->type,
				'sortby'      => 'value',
			);
		}

		return empty( $ret ) ? null : $ret;
	}

	public function fieldColumnableColumn( IField $field, IEntity $entity, $column = '' ) {
		$values = $entity->getFieldValue( $field->getFieldName() );
		if ( empty( $values[0][ $column ] ) ) {
			return 0;
		}

		if ( $this->_application->getPlatform()->getName() !== 'WordPress' ) {
			return $values[0][ $column ];
		}

		if ( ( ! $bundle = $this->_application->Entity_Bundle( $entity ) )
			|| ( ! $child_bundle = $this->_application->Entity_Bundle( $column, $bundle->group ) )
		) {
			return $values[0][ $column ];
		}

		return '<a href="' . admin_url( 'edit.php?post_type=' . $child_bundle->name . '&drts_wp_post_parent=' . $entity->getId() ) . '">' . $values[0][ $column ] . '</a>';
	}

	public function fieldComparableItemLabels( IField $field ) {
		$ret = array();
		foreach ( $this->_getChildBundleNames( $field, true ) as $child_bundle_name ) {
			if ( ! $child_bundle = $this->_application->Entity_Bundle( $child_bundle_name ) ) {
				continue;
			}

			$ret[ $child_bundle->type ] = $child_bundle->getLabel();
		}

		return $ret;
	}

	public function fieldComparableItemValues( IField $field, IEntity $entity, $html = true ) {
		$value = $entity->getSingleFieldValue( $field->getFieldName() );
		$ret   = array();
		foreach ( $this->_getChildBundleNames( $field, true ) as $child_bundle_name ) {
			if ( ! $child_bundle = $this->_application->Entity_Bundle( $child_bundle_name ) ) {
				continue;
			}

			$count                      = empty( $value[ $child_bundle->type ] ) ? 0 : (int) $value[ $child_bundle->type ];
			$ret[ $child_bundle->type ] = $count ? sprintf( _n( $child_bundle->getLabel( 'count' ), $child_bundle->getLabel( 'count2' ), $count, 'directories-pro' ), $count ) : '';
		}
		return $ret;
	}

	protected function _getChildBundleNames( IField $field, $publicOnly = true ) {
		if ( ( ! $bundle = $this->_application->Entity_Bundle( $field->getBundleName() ) )
			|| ( ! $child_bundle_types = $this->_application->Entity_BundleTypes_children( $bundle->type, $publicOnly ) )
		) {
			return array();
		}

		$ret = array();
		foreach ( $child_bundle_types as $child_bundle_type ) {
			try {
				$child_bundle = $this->_application->Entity_Bundle( $child_bundle_type, $bundle->group, true );
			} catch ( IException $e ) {
				continue;
			}

			$ret[] = $child_bundle->name;
		}

		return $ret;
	}
}
