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

use SabaiApps\Directories\Component\Entity\FieldType\IParentFieldType;
use SabaiApps\Directories\Component\Field\Type\AbstractType;
use SabaiApps\Directories\Component\Field\Type\IColumnable;
use SabaiApps\Directories\Component\Field\Type\IRestrictable;
use SabaiApps\Directories\Component\Field\Type\ITitle;
use SabaiApps\Directories\Component\Entity\FieldType\ITitleFieldType;
use SabaiApps\Directories\Component\Field\IField;
use SabaiApps\Directories\Component\Entity\Type\IEntity;
use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Field\Type\SaveNotesTrait;

abstract class AbstractOrderFieldType extends AbstractType implements
	IColumnable,
	IRestrictable,
	ITitle,
	ITitleFieldType,
	IParentFieldType {

	use SaveNotesTrait;

	protected $_label,
		$_requiredKeys     = array( 'plan_id' ),
		$_persistentValues = array(
			'number'             => '',
			'status'             => '',
			'action'             => '',
			'gateway'            => '',
			'gateway_item_id'    => '',
			'parent_entity_id'   => 0,
			'parent_entity_type' => '',
		);

	public function __construct( Application $application, $name, $label ) {
		parent::__construct( $application, $name );
		$this->_label = $label;
	}

	protected function _fieldTypeInfo() {
		return array(
			'label'      => $this->_label,
			'creatable'  => false,
			'disablable' => false,
			'requirable' => false,
		);
	}

	public function fieldTypeSchema( array $settings = array() ) {
		return array(
			'columns' => array(
				'number'             => array(
					'type'    => Application::COLUMN_VARCHAR,
					'length'  => 100,
					'notnull' => true,
					'was'     => 'number',
					'default' => '',
				),
				'status'             => array(
					'type'    => Application::COLUMN_VARCHAR,
					'length'  => 20,
					'notnull' => true,
					'was'     => 'status',
					'default' => '',
				),
				'gateway'            => array(
					'type'    => Application::COLUMN_VARCHAR,
					'length'  => 20,
					'notnull' => true,
					'was'     => 'gateway',
					'default' => '',
				),
				'gateway_item_id'    => array(
					'type'    => Application::COLUMN_VARCHAR,
					'length'  => 100,
					'notnull' => true,
					'was'     => 'gateway_item_id',
					'default' => '',
				),
				'plan_id'            => array(
					'type'    => Application::COLUMN_INTEGER,
					'length'  => 10,
					'notnull' => true,
					'was'     => 'plan_id',
					'default' => '',
				),
				'data'               => array(
					'type'    => Application::COLUMN_JSON,
					'notnull' => false,
					'default' => null,
				),
				'notes'              => array(
					'type'    => Application::COLUMN_JSON,
					'notnull' => false,
					'default' => null,
				),
				'parent_entity_id'   => array(
					'type'    => Application::COLUMN_INTEGER,
					'length'  => 20,
					'notnull' => true,
					'was'     => 'parent_entity_id',
					'default' => '',
				),
				'parent_entity_type' => array(
					'type'    => Application::COLUMN_VARCHAR,
					'length'  => 40,
					'notnull' => true,
					'was'     => 'parent_entity_type',
					'default' => '',
				),
			),
			'indexes' => array(
				'number'             => array(
					'unique' => true,
					'fields' => array( 'number' => array( 'sorting' => 'ascending' ) ),
					'was'    => 'number',
				),
				'status'             => array(
					'fields' => array( 'status' => array( 'sorting' => 'ascending' ) ),
					'was'    => 'status',
				),
				'gateway'            => array(
					'fields' => array( 'gateway' => array( 'sorting' => 'ascending' ) ),
					'was'    => 'gateway',
				),
				'plan_id'            => array(
					'fields' => array( 'plan_id' => array( 'sorting' => 'ascending' ) ),
					'was'    => 'plan_id',
				),
				'parent_entity_id'   => array(
					'fields' => array( 'parent_entity_id' => array( 'sorting' => 'ascending' ) ),
					'was'    => 'parent_entity_id',
				),
				'parent_entity_type' => array(
					'fields' => array( 'parent_entity_type' => array( 'sorting' => 'ascending' ) ),
					'was'    => 'parent_entity_type',
				),
			),
		);
	}

	public function fieldTypeOnSaveValues( IField $field, array $values, ?array $currentValues = null, array &$extraArgs = array() ) {
		$value = array_shift( $values ); // single entry allowed for this field
		if ( ! is_array( $value ) ) {
			if ( $value === null ) {
				return; // do nothing
			}

			return array( false ); // delete
		}

		// Make sure required properties are set
		foreach ( $this->_requiredKeys as $required_key ) {
			if ( ! isset( $value[ $required_key ] ) ) {
				if ( empty( $currentValues[0][ $required_key ] ) ) {
					return array( false ); // delete
				}

				$value[ $required_key ] = $currentValues[0][ $required_key ];
			} elseif ( empty( $value[ $required_key ] ) ) {
				return array( false ); // delete
			}
		}

		// Keep current values unless explicitly changed
		foreach ( $this->_persistentValues as $key => $default_value ) {
			if ( isset( $value[ $key ] ) ) {
				continue;
			}

			$value[ $key ] = $currentValues[0][ $key ] ?? $default_value;
		}

		// Update and serialize data
		if ( ! isset( $value['data'] ) ) {
			if ( ! empty( $currentValues[0]['data'] ) ) {
				$value['data'] = $currentValues[0]['data'];
			}
		}

		// Update and serialize notes
		$this->_saveNotes( $value, $currentValues );

		return array( $value );
	}

	public function fieldColumnableInfo( IField $field ) {
		return array(
			'id'      => array(
				'label'      => $field->Bundle->getLabel( 'singular' ),
				'sortby'     => 'id',
				'is_primary' => true,
			),
			'status'  => array(
				'label' => __( 'Status', 'directories-pro' ),
			),
			'plan'    => array(
				'label' => __( 'Plan name', 'directories-pro' ),
			),
			'gateway' => array(
				'label' => __( 'Payment method', 'directories-pro' ),
			),
		);
	}

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

		switch ( $column ) {
			case 'id':
				$ret = '<strong><a href="%%admin_permalink_url%%">%%title%%</a></strong>';
				if ( $parent_entity = $this->_application->Entity_Entity( $values[0]['parent_entity_type'], $values[0]['parent_entity_id'] ) ) {
					$ret .= ' - <a href="' . $this->_application->Entity_AdminUrl( $parent_entity ) . ' ">' . $this->_application->H( $this->_application->Entity_Title( $parent_entity ) ) . '</a>';
				}
				return $ret;
			case 'status':
				return isset( $values[0]['status'] ) ? $this->_getStatusLabel( $values[0]['status'] ) : '';
			case 'plan':
				if ( empty( $values[0]['plan_id'] )
					|| ( ! $plan = $this->_application->Entity_Entity( 'post', $values[0]['plan_id'] ) )
					|| $plan->getBundleType() !== 'paymentgateway_plan'
				) {
					return '';
				}

				return $this->_application->H( $plan->getTitle() );
			case 'gateway':
				if ( empty( $values[0]['gateway'] ) ) {
					return '';
				}

				$settings = $this->_application->Payment_Components_impl( 'default' )->getSettings();
				$gateway  = $values[0]['gateway'];
				return isset( $settings['gateways']['options'][ $gateway ] )
					? $this->_application->H( $settings['gateways']['options'][ $gateway ] )
					: '<span class="' . DRTS_BS_PREFIX . 'text-danger">' . $this->_application->H( $gateway ) . '</span>';
		}
	}

	abstract protected function _getStatusLabel( $status, $html = true, $badge = true );
	abstract protected function _getStatuses();

	public function fieldRestrictableOptions( IField $field ) {
		$statuses = array( '' => array( 'label' => __( 'Status', 'directories-pro' ) ) );
		foreach ( $this->_getStatuses() as $status => $status_info ) {
			$statuses[ $status ] = $status_info['label'];
		}
		$settings = $this->_application->Payment_Components_impl( 'default' )->getSettings();
		$gateways = array( '' => array( 'label' => __( 'Payment method', 'directories-pro' ) ) ) + $settings['gateways']['options'];

		$options = array(
			'status'  => $statuses,
			'gateway' => $gateways,
		);

		if ( $bundle = $field->Bundle ) {
			$content_bundle_names = array();
			foreach ( $this->_application->Entity_Bundles( null, $bundle->group ) as $content_bundle ) {
				if ( empty( $content_bundle->info['payment_enable'] ) ) {
					continue;
				}

				$content_bundle_names[] = $content_bundle->name;
			}
			foreach ( $content_bundle_names as $content_bundle_name ) {
				if ( $plans = $this->_application->Payment_Plans( $content_bundle_name, $this->_getPaymentPlanTypes( $content_bundle_name ) ) ) {
					foreach ( array_keys( $plans ) as $plan_id ) {
						$plans[ $plan_id ] = $plans[ $plan_id ]->paymentPlanTitle();
					}
					$options['plan_id'] = array( '' => array( 'label' => __( 'Payment Plan', 'directories-pro' ) ) ) + $plans;
				}
			}
		}

		return $options;
	}

	protected function _getPaymentPlanTypes( $contentBundleName ) {
		return $this->_application->Filter( 'payment_base_plan_types', array( 'base' ), array( $contentBundleName ) );
	}

	public function fieldRestrictableRestrict( IField $field, $value, $name ) {
		return array( 'column' => $name );
	}

	public function fieldTitle( IField $field, array $values ) {
		return isset( $values[0]['number'] ) && strlen( $values[0]['number'] ) ? $values[0]['number'] : null;
	}

	public function entityFieldTypeGetTitle( IField $field, IEntity $entity ) {
		return $entity->getSingleFieldValue( $field->getFieldName(), 'number' );
	}

	public function entityFieldTypeGetParentId( IField $field, IEntity $entity ) {
		return $entity->getSingleFieldValue( $field->getFieldName(), 'parent_entity_id' );
	}

	public function entityFieldTypeGetParentType( IField $field, IEntity $entity ) {
		return $entity->getSingleFieldValue( $field->getFieldName(), 'parent_entity_type' );
	}
}
