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

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\Application;

class PriceType extends AbstractType implements
	ISortable,
	IQueryable,
	IHumanReadable,
	IConditionable,
	ISchemable,
	IWpRestApi,
	IComparable {

	use ConditionableNumberTrait;
	use QueryableNumberTrait;
	use ComparableStringTrait;

	protected $_valueColumn = 'value';

	protected function _fieldTypeInfo() {
		return array(
			'label'            => __( 'Price', 'directories-pro' ),
			'default_settings' => array(
				'min'        => null,
				'max'        => null,
				'currencies' => array( 'USD' ),
			),
			'icon'             => 'fas fa-money-bill-alt',
		);
	}

	public function fieldTypeSettingsForm( $fieldType, Bundle $bundle, array $settings, array $parents = array(), array $rootParents = array() ) {
		return array(
			'#element_validate' => array( array( $this, 'validateMinMaxSettings' ) ),
			'min'               => array(
				'#type'          => 'number',
				'#title'         => __( 'Minimum', 'directories-pro' ),
				'#description'   => __( 'The minimum value allowed in this field.', 'directories-pro' ),
				'#size'          => 10,
				'#default_value' => $settings['min'],
				'#numeric'       => true,
				'#step'          => 0.01,
			),
			'max'               => array(
				'#type'          => 'number',
				'#title'         => __( 'Maximum', 'directories-pro' ),
				'#description'   => __( 'The maximum value allowed in this field.', 'directories-pro' ),
				'#size'          => 10,
				'#default_value' => $settings['max'],
				'#numeric'       => true,
				'#step'          => 0.01,
			),
			'currencies'        => array(
				'#type'          => 'sortablecheckboxes',
				'#title'         => __( 'Currencies', 'directories-pro' ),
				'#options'       => $this->_application->System_Currency_options(),
				'#default_value' => $settings['currencies'],
				'#columns'       => 3,
			),
		);
	}

	public function fieldTypeSchema( array $settings = array() ) {
		return array(
			'columns' => array(
				'value'    => array(
					'type'     => Application::COLUMN_DECIMAL,
					'notnull'  => true,
					'length'   => 18,
					'scale'    => 3,
					'unsigned' => false,
					'was'      => 'value',
					'default'  => 0,
				),
				'currency' => array(
					'type'    => Application::COLUMN_VARCHAR,
					'length'  => 3,
					'notnull' => true,
					'was'     => 'currency',
					'default' => '',
				),
			),
			'indexes' => array(
				'value'    => array(
					'fields' => array( 'value' => array( 'sorting' => 'ascending' ) ),
					'was'    => 'value',
				),
				'currency' => array(
					'fields' => array( 'currency' => array( 'sorting' => 'ascending' ) ),
					'was'    => 'currency',
				),
			),
		);
	}

	public function fieldTypeOnSaveValues( IField $field, array $values, ?array $currentValues = null, array &$extraArgs = array() ) {
		$settings         = (array) $field->getFieldSettings();
		$default_currency = empty( $settings['currencies'] ) || ! is_array( $settings['currencies'] ) ? 'USD' : $settings['currencies'][0];
		$ret              = array();
		foreach ( $values as $value ) {
			if ( ! is_array( $value )
				|| empty( $value )
				|| ! isset( $value[ $this->_valueColumn ] )
				|| ! is_numeric( $value[ $this->_valueColumn ] )
			) {
				continue;
			}

			if ( empty( $value['currency'] ) ) {
				$value['currency'] = $default_currency;
			} elseif ( ! in_array( $value['currency'], (array) $settings['currencies'] ) ) {
					continue;
			}

			$ret[] = array(
				'currency'          => $value['currency'],
				$this->_valueColumn => $value[ $this->_valueColumn ],
			);
		}

		return $ret;
	}

	public function fieldTypeIsModified( IField $field, $valueToSave, $currentLoadedValue ) {
		if ( count( $currentLoadedValue ) !== count( $valueToSave ) ) {
			return true;
		}

		foreach ( array_keys( $currentLoadedValue ) as $key ) {
			if ( count( $currentLoadedValue[ $key ] ) !== count( $valueToSave[ $key ] )
				|| array_diff_assoc( $currentLoadedValue[ $key ], $valueToSave[ $key ] )
			) {
				return true;
			}
		}
		return false;
	}

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

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

	public function fieldSchemaProperties( IField $field ) {
		return array( 'priceRange', 'price', 'priceCurrency', 'baseSalary' );
	}

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

		switch ( $property ) {
			case 'priceRange':
				return $this->_getFormattedValues( $field, $entity, array( $value ) );
			case 'price':
				return $value['value'];
			case 'priceCurrency':
				return $value['currency'];
			case 'baseSalary':
				return array(
					array(
						'@type'    => 'MonetaryAmount',
						'value'    => $value['value'],
						'currency' => $value['currency'],
					),
				);
		}
	}

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

		return implode( isset( $separator ) ? $separator : ', ', $values );
	}

	protected function _getFormattedValues( IField $field, IEntity $entity, ?array $values = null ) {
		if ( ! isset( $values )
			&& ( ! $values = $entity->getFieldValue( $field->getFieldName() ) )
		) {
			return array();
		}

		foreach ( array_keys( $values ) as $i ) {
			$values[ $i ] = $this->_application->System_Currency_format( $values[ $i ]['value'], $values[ $i ]['currency'] );
		}

		return $values;
	}

	public function fieldWpRestApiSchema( IField $field ) {
		return array(
			'type'  => 'array',
			'items' => array(
				'type' => 'string',
			),
		);
	}

	public function fieldWpRestApiGetValue( IField $field, IEntity $entity, $request ) {
		return $this->_getFormattedValues( $field, $entity );
	}
}
