<?php
namespace Drupal\basket\Admin\Page;

use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\AppendCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\Url;
use Drupal\Core\Render\Markup;
use Drupal\Core\Ajax\CloseModalDialogCommand;
use Drupal\Core\Ajax\RedirectCommand;

class Order{
	
	protected static $Basket;
	protected static $OrderClass;
	protected static $Order;
	protected static $OrderNode;
	protected static $LoadTab = 'order_data';
	protected static $viewType;

	function __construct($orderId = NULL, $view = 'full'){
		self::$Basket = \Drupal::service('Basket');
		self::$OrderClass = self::$Basket->Orders($orderId);
		self::$Order = self::$OrderClass->load();
		if(!empty(self::$Order->nid)){
			self::$OrderNode = \Drupal\node\Entity\Node::load(self::$Order->nid);
			self::$OrderNode->basket_admin_process = self::$Order;
		}
		if(!empty(self::$Order) && is_numeric(self::$Order->id) && empty(self::$Order->first_view_uid) && $view == 'full'){
			self::$OrderClass->set('first_view_uid', \Drupal::currentUser()->id());
			self::$OrderClass->save();
		}
		if(!empty(self::$Order->id) && self::$Order->id == 'NEW'){
			self::$OrderNode = \Drupal::entityTypeManager()
                    ->getStorage('node')
                    ->create([
                    	'type'		=> 'basket_order',
                		'status'    => FALSE,
                		'title'     => 'Order',
                    ]);
            self::$OrderNode->basket_admin_process = self::$Order; 
            self::$OrderNode->basket_create_order = TRUE; 
		}
		$query = \Drupal::request()->query->all();
		if(!empty($query['tab'])){
			self::$LoadTab = $query['tab'];
		}
	}
	/*
	 edit
	*/
	public static function edit(){
		if(empty(self::$Order)){
			return self::$Basket->getError(404);
		}
		if(!\Drupal::currentUser()->hasPermission('basket access_edit_order')){
			return self::$Basket->getError(403);
		}
		self::$viewType = 'edit';
		return [
			'#prefix'		=> '<div class="basket_table_wrap">',
			'#suffix'		=> '</div>',
			[
				'#prefix'		=> '<div class="b_title">',
				'#suffix'		=> '</div>',
				'#markup'		=> self::$Basket->Translate()->t('Order ID: @num@', ['@num@' => \Drupal::service('Basket')->Orders(self::$Order->id)->getId()]),
				self::allLinks()
			],[
				'#prefix'		=> '<div class="b_content">',
				'#suffix'		=> '</div>',
				'order_info'	=> self::getOrderInfoBlock(),
				'tabs'			=> self::getTabs(self::$LoadTab),
				'content'		=> [
					'#prefix'		=> '<div id="basket_order_edit_tab_content">',
					'#suffix'		=> '</div>',
					self::getContent(self::$LoadTab)
				]
			],
			'#cache'			=> [
				'max-age'			=> 0
			]
		];
	}
	/*
	 view
	*/
	public static function view(){
		self::$viewType = 'view';
		if(empty(self::$Order)){
			return self::$Basket->getError(404);
		}
		return [
			'#prefix'		=> '<div class="basket_table_wrap">',
			'#suffix'		=> '</div>',
			[
				'#prefix'		=> '<div class="b_title">',
				'#suffix'		=> '</div>',
				'#markup'		=> self::$Basket->Translate()->t('Order ID: @num@', ['@num@' => \Drupal::service('Basket')->Orders(self::$Order->id)->getId()]),
				self::allLinks()
			],[
				'#prefix'		=> '<div class="b_content">',
				'#suffix'		=> '</div>',
				'order_info'	=> self::getOrderInfoBlock(),
				'order_view'	=> self::getOrderInfoBlock('order_view_info'),
			],
			'#cache'			=> [
				'max-age'			=> 0
			]
		];
	}
	/*
	 allLinks
	*/
	public static function allLinks(){
		if(empty(self::$Order)) return [];
		$links = [
			'edit'		=> self::getEditLink(),
			'delete'	=> self::getDeleteLink(),
			'restore'	=> self::getRestoreLink(),
			'permDelete'=> self::getPermanentlyDeleteLink(),
			'waybill'	=> self::$Basket->Waybill(self::$Order->id)->getLink(),
			'export'	=> \Drupal\basket\BasketExport::getLinkOrderExport(self::$Order->id)
		];
		// Alter
		\Drupal::moduleHandler()->alter('basket_order_links', $links, self::$Order);
		// ---
		return $links;
	}
	/*
	 getEditLink
	*/
	public static function getEditLink(){
		if(self::$viewType == 'edit')	return [];
		$context = self::getEditLinkContext();
		if(empty($context)) return [];
		return [
			'#type'         => 'inline_template',
            '#template'		=> '<a href="{{ url }}" class="button--link"><span class="ico">{{ ico|raw }}</span> {{ text }}</a>',
            '#context'     	=> $context
		];
	}
	/*
	 getEditLinkContext
	*/
	public static function getEditLinkContext(){
		if(empty(self::$Order)) return [];
		if(!\Drupal::currentUser()->hasPermission('basket access_edit_order')) return [];
		if(!empty(self::$Order->is_delete)) return [];
		return [
			'text'			=> self::$Basket->Translate()->t('Edit'),
			'ico'			=> self::$Basket->getIco('edit.svg'),
			'url'			=> Url::fromRoute('basket.admin.pages', ['page_type' => 'orders-edit-'.self::$Order->id])->toString()
		];
	}
	/*
	 getDeleteLink
	*/
	public static function getDeleteLink(){
		$context = self::getDeleteContext();
		if(empty($context)) return [];
		return [
			'#type'         => 'inline_template',
            '#template'     => '<a href="javascript:void(0);" class="button--link" onclick="{{ onclick }}" data-post="{{ post }}"><span class="ico">{{ ico|raw }}</span> {{ text }}</a>',
            '#context'     	=> $context
		];
	}
	/*
	 getDeleteContext
	*/
	public static function getDeleteContext(){
		if(empty(self::$Order)) return [];
		if(!empty(self::$Order->is_delete)) return [];
		if(self::$Order->id == 'NEW') return [];
		if(!\Drupal::currentUser()->hasPermission('basket access_delete_order')) return [];
		return [
			'text'			=> self::$Basket->Translate()->t('Delete'),
			'ico'			=> self::$Basket->getIco('trash.svg'),
			'onclick'		=> 'basket_admin_ajax_link(this, \''.Url::fromRoute('basket.admin.pages', ['page_type' => 'api-orders-delete'])->toString().'\')',
			'post'			=> json_encode([
				'orderId'		=> self::$Order->id
			]),
		];
	}
	/*
	 getRestoreLink
	*/
	public static function getRestoreLink(){
		$context = self::getRestoreContext();
		if(empty($context)) return [];
		return [
			'#type'         => 'inline_template',
            '#template'     => '<a href="javascript:void(0);" class="button--link" onclick="{{ onclick }}" data-post="{{ post }}"><span class="ico">{{ ico|raw }}</span> {{ text }}</a>',
            '#context'     	=> $context
		];
	}
	/*
	 getRestoreContext
	*/
	public static function getRestoreContext(){
	 	if(empty(self::$Order->is_delete)) return [];
	 	if(!\Drupal::currentUser()->hasPermission('basket access_restore_order')) return [];
	 	return [
	 		'text'			=> self::$Basket->Translate()->t('Restore'),
	 		'ico'			=> self::$Basket->getIco('restore.svg'),
	 		'onclick'		=> 'basket_admin_ajax_link(this, \''.Url::fromRoute('basket.admin.pages', ['page_type' => 'api-orders-restore'])->toString().'\')',
			'post'			=> json_encode([
				'orderId'		=> self::$Order->id
			]),
	 	];
	}
	/*
	 getPermanentlyDeleteLink
	*/
	public static function getPermanentlyDeleteLink(){
		$context = self::getPermanentlyDeleteContext();
		if(empty($context)) return [];
		return [
			'#type'         => 'inline_template',
            '#template'     => '<a href="javascript:void(0);" class="button--link" onclick="{{ onclick }}" data-post="{{ post }}"><span class="ico">{{ ico|raw }}</span> {{ text }}</a>',
            '#context'     	=> $context
		];
	}
	/*
	 getPermanentlyDeleteContext
	*/
	public static function getPermanentlyDeleteContext(){
		if(empty(self::$Order->is_delete)) return [];
		if(!\Drupal::currentUser()->hasPermission('basket access_trash_clear_page')) return [];
		return [
			'text'			=> self::$Basket->Translate()->t('Permanently remove'),
			'ico'			=> self::$Basket->getIco('trash.svg'),
			'onclick'		=> 'basket_admin_ajax_link(this, \''.Url::fromRoute('basket.admin.pages', ['page_type' => 'api-orders-permanently_delete'])->toString().'\')',
			'post'			=> json_encode([
				'orderId'		=> self::$Order->id
			]),
		];
	}
	/*
	 getOrderInfoBlock
	*/
	public static function getOrderInfoBlock($template = 'order_info'){
		$settings = self::$Basket->getSettings('templates', $template);
		if(empty($settings['config']['template'])) {
			return [
				'#prefix'		=> '<div>',
				'#suffix'		=> '</div>'
			];
		}
		$html = [
			'#type'			=> 'inline_template',
			'#template'		=> $settings['config']['template'],
			'#context'		=> self::$Basket->MailCenter()->getContext($template, [
				'order'			=> self::$Order
			])
		];
		$html = \Drupal::service('renderer')->render($html);
		$html = \Drupal::token()->replace(
			$html, [
				'user'		=> !empty(self::$OrderNode) ? \Drupal\user\Entity\User::load(self::$OrderNode->get('uid')->target_id) : NULL,
				'node'		=> self::$OrderNode
			], [
				'clear' 	=> TRUE
			]
		);
		return [
			'#markup'		=> Markup::create($html),
			'#prefix'		=> '<div id="order_info_block">',
			'#suffix'		=> '</div>'
		];
	}
	/*
	 getTabs
	*/
	private static function getTabs($LoadTab){
		$items = [
			'order_data'	=> [
				'name'			=> self::$Basket->Translate()->t('Order data'),
				'disabled'		=> FALSE
			],
			'products'		=> [
				'name'			=> self::$Basket->Translate()->t('Products'),
				'disabled'		=> self::$Order->id == 'NEW'
			]
		];
		$items[$LoadTab]['class'][] = 'is-active';
		return [
			'#type'			=> 'inline_template',
			'#template'		=> '<div class="order_tabs">
				{% for id, item in items %}
					<a href="javascript:void(0);" class="{{ item.class|join(\' \') }}" onclick="{% if not item.disabled %}{{ onclick }}{% endif %}" data-tab_id="{{ id }}" data-post="{{ {\'tab\': id, \'orderId\': order.id }|json_encode }}">{{ item.name }}</a>
				{% endfor %}
			</div>',
			'#context'		=> [
				'items'			=> $items,
				'onclick'		=> 'basket_order_edit_load_tab(this, \''.Url::fromRoute('basket.admin.pages', ['page_type' => 'api-orders-load_tab'])->toString().'\')',
				'order'		=> self::$Order
			]
		];
	}
	/* 
	 getContent
	*/
	private static function getContent($LoadTab){
		$element = [
			'tab'		=> [
				'#prefix'		=> '<div class="tab_content" data-tab-content="'.$LoadTab.'">',
				'#suffix'		=> '</div>',
			]
		];
		if(!empty(self::$Order->is_delete)){
			$element['tab'][] = self::$Basket->getError(403);
			return $element;
		}
		if(empty(self::$OrderNode)){
			$element['tab'][] = self::$Basket->getError(404);
		} else {
			switch($LoadTab){
				case'order_data':
					$element['tab'][] = \Drupal::service('entity.form_builder')->getForm(self::$OrderNode);
				break;
				case'products':
					if(empty(self::$OrderNode->id())){
						$element['tab'][] = self::$Basket->getError(404);
					} else {

						$form = new \Drupal\basket\Admin\Form\Order\ItemsForm(self::$Order);
						$element['tab'][] = \Drupal::formBuilder()->getForm($form);
					}
				break;
			}
		}
		return $element;
	}
	/*
	 nodeFormAlter
	*/
	public static function nodeFormAlter(&$form, $form_state){
		$storage = $form_state->getStorage();
		if(empty($storage['FormOrder']) && !empty(self::$Order)){
			$storage['FormOrder'] = self::$Order;
			$form_state->setStorage($storage);
		}
		$form['tab'] = [
			'#type'			=> 'hidden',
			'#value'		=> 'order_data'
		];
		$form['orderId'] = [
			'#type'			=> 'hidden',
			'#value'		=> !empty(self::$Order) ? self::$Order->id : 'NEW'
		];
		$form['actions']['submit']['#name'] = 'adminSave';
		$form['actions']['submit']['#submit'][] = __CLASS__.'::orderFullSubmit';
		$form['actions']['submit']['#ajax'] = [
            'wrapper'       => 'basket_node_basket_order_form_ajax_wrap',
            'callback'      => '\\'.__CLASS__.'::submitAjax',
            'url'           => new Url('basket.admin.pages', ['page_type' => 'api-orders-basket_order_form']),
            'options'       => [
                'query'         => \Drupal::request()->query->All() + [FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]
            ]
        ];
        $entity = $form_state->getBuildInfo()['callback_object']->getEntity();
        if(!empty($entity->basket_create_order)){
        	$options = self::$Basket->Currency()->getOptions();
        	$form['order_set_currency'] = [
        		'#type'			=> 'select',
        		'#title'		=> self::$Basket->Translate()->t('Currency'),
        		'#required'		=> TRUE,
        		'#options'		=> $options,
        		'#weight'		=> 100,
        		'#default_value'=> !empty($options) ? key($options) : NULL
        	];
        	$form['actions']['submit']['#value'] = self::$Basket->Translate()->t('Save and add products');
        }
	}
	public static function orderFullSubmit($form, $form_state){
		// Finish save order
		$storage = $form_state->getStorage();
		if(!empty($storage['FormOrder'])){
			$orderClass = \Drupal::service('Basket')->Orders($storage['FormOrder']->id);
			$order = $orderClass->load();
			if(!empty($order)){
				
				$storage['FormOrder'] = clone $order;

				$orderClass->refresh();
				$orderClass->replaceOrder($storage['FormOrder'], TRUE);
				$orderClass->save();

				$form_state->setStorage($storage);
			}
		}
		// ---
	}
	/*
	 submitAjax
	*/
	public static function submitAjax($form, $form_state){
		$response = new AjaxResponse();
		$entity = $form_state->getBuildInfo()['callback_object']->getEntity();
		if($form_state->hasAnyErrors()){
			unset($form['#prefix'], $form['#suffix']);
		    $response->addCommand(new HtmlCommand('#'.$form['actions']['submit']['#ajax']['wrapper'], $form));
		} else {
			if(!empty($entity->basket_create_order)){
				// Create order
				$orderId = \Drupal::database()->insert('basket_orders')
								->fields([
									'nid'		=> $entity->id(),
									'price'		=> 0,
									'goods'		=> 0,
									'currency'	=> $form_state->getValue('order_set_currency'),
									'status'	=> self::$Basket->Term()->getDefaultNewOrder('status'),
									'fin_status'=> self::$Basket->Term()->getDefaultNewOrder('fin_status'),
								])
								->execute();
				// Message
				\Drupal::messenger()->deleteAll();
				$response->addCommand(new RedirectCommand(Url::fromRoute('basket.admin.pages', [
					'page_type' 		=> 'orders-edit-'.$orderId
				],[
					'query'				=> [
						'tab'				=> 'products'
					]
				])->toString()));
			} else {
				// Message
				\Drupal::messenger()->deleteAll();
				$response->addCommand(new InvokeCommand(NULL, 'NotyGenerate', ['status', self::$Basket->Translate()->t('Settings saved.')]));
				// Return form
				unset($form['#prefix'], $form['#suffix']);
		    	$response->addCommand(new HtmlCommand('#'.$form['actions']['submit']['#ajax']['wrapper'], $form));
		    	$response->addCommand(new InvokeCommand('input[name="changed"]', 'val', [$entity->get('changed')->value]));

		    	$response->addCommand(new ReplaceCommand('#order_info_block', self::getOrderInfoBlock()));
			}
		}
		return $response;
	}
	/*
	 ApiResponseAlter
	*/
	public static function ApiResponseAlter($response, $api_type = NULL, $api_subtype = NULL){
		switch($api_type){
			case'orders':
				switch($api_subtype){
					case'delete':
						if(!empty(self::$Order->nid) && \Drupal::currentUser()->hasPermission('basket access_delete_order')){
							if(!empty($_POST['confirm'])){
								/*Update order*/
								self::$OrderClass->set('is_delete', 1);
								self::$OrderClass->save();
								/**/
								\Drupal::messenger()->addMessage(
									self::$Basket->Translate()->t('Order №@num@ deleted successfully.', ['@num@' => \Drupal::service('Basket')->Orders(self::$Order->id)->getId()]), 
									'status'
								);
								$response->addCommand(new InvokeCommand('body', 'append', ['<script>location.reload();</script>']));
							} else {
								\Drupal::service('BasketPopup')->openModal(
						            $response,
						           	self::$Basket->Translate()->t('Delete').' "'.self::$Basket->Translate()->t('Order ID: @num@', ['@num@' => \Drupal::service('Basket')->Orders(self::$Order->id)->getId()]).'"', 
				                    \Drupal\basket\Admin\BasketDeleteConfirm::confirmContent([
				                        'onclick'       => 'basket_admin_ajax_link(this, \''.Url::fromRoute('basket.admin.pages', ['page_type' => 'api-orders-delete'])->toString().'\')',
				                        'post'          => json_encode([
				                            'orderId'    => self::$Order->id,
				                            'confirm'       => 1
				                        ]),
				                    ]),
				                    [
						                'width' => 400,
						                'class' => []
						            ]
						        );
							}
						}
					break;
					case'permanently_delete':
						if(!empty(self::$Order->nid) && \Drupal::currentUser()->hasPermission('basket access_trash_clear_page')){
							if(!empty($_POST['confirm'])){
								/*Update order*/
								self::$OrderClass->delete();
								/**/
								\Drupal::messenger()->addMessage(
									self::$Basket->Translate()->t('Order №@num@ deleted successfully.', ['@num@' => \Drupal::service('Basket')->Orders(self::$Order->id)->getId()]), 
									'status'
								);
								$response->addCommand(new RedirectCommand(Url::fromRoute('basket.admin.pages', ['page_type' => 'trash'])->toString()));
							} else {
								\Drupal::service('BasketPopup')->openModal(
						            $response,
						           	self::$Basket->Translate()->t('Delete').' "'.self::$Basket->Translate()->t('Order ID: @num@', ['@num@' => \Drupal::service('Basket')->Orders(self::$Order->id)->getId()]).'"', 
				                    \Drupal\basket\Admin\BasketDeleteConfirm::confirmContent([
				                        'onclick'       => 'basket_admin_ajax_link(this, \''.Url::fromRoute('basket.admin.pages', ['page_type' => 'api-orders-permanently_delete'])->toString().'\')',
				                        'post'          => json_encode([
				                            'orderId'    => self::$Order->id,
				                            'confirm'       => 1
				                        ]),
				                    ]),
				                    [
						                'width' => 400,
						                'class' => []
						            ]
						        );
							}
						}
					break;
					case'restore':
						if(!empty(self::$Order->nid) && \Drupal::currentUser()->hasPermission('basket access_restore_order')){
							/*Update order*/
							self::$OrderClass->set('is_delete', NULL);
							self::$OrderClass->save();
							/**/
							\Drupal::messenger()->addMessage(
								self::$Basket->Translate()->t('Order №@num@ successfully restored.', ['@num@' => \Drupal::service('Basket')->Orders(self::$Order->id)->getId()]), 
								'status'
							);
							$response->addCommand(new InvokeCommand('body', 'append', ['<script>location.reload();</script>']));
						}
					break;
					case'load_tab':
						if(!empty($_POST['tab']) && !empty(self::$Order)){
							$content = self::getContent($_POST['tab']);
							$response->addCommand(new AppendCommand('#basket_order_edit_tab_content', $content));
						}
					break;
					case'basket_order_items_form':
						if(!empty($_POST['orderId'])){
							$form = new \Drupal\basket\Admin\Form\Order\ItemsForm(self::$Order);
							return \Drupal::formBuilder()->getForm($form);
						}
					break;
					case'basket_order_form':
						if(!empty(self::$OrderNode)){
							return \Drupal::service('entity.form_builder')->getForm(self::$OrderNode);
						}
					break;
					case'add_goods_popup':
						\Drupal::service('BasketPopup')->openModal(
				            $response,
				            self::$Basket->Translate()->t('Add a product'),
				            [
				            	'#prefix'		=> '<div class="basket_table_wrap">',
				            	'#suffix'		=> '</div>',
				            	[
				            		'#prefix'		=> '<div class="b_content">',
									'#suffix'		=> '</div>',
				            		'view'			=> self::$Basket->getView('basket', 'block_2')
				            	]
				            ],
				            [
				                'width' 	=> 960,
				                'class' 	=> []
				            ]
				        );
					break;
					case'addOrderItem':
						$response->addCommand(new AppendCommand('body', '<script>'.\Drupal::service('BasketPopup')->getCloseOnclick().'</script>'));
						if(!empty($_POST['addItem'])){
							$response->addCommand(new InvokeCommand('textarea[name="addItem"]', 'val', [json_encode($_POST['addItem'])]));
							$response->addCommand(new InvokeCommand('textarea[name="addItem"]', 'trigger', ['change']));
						}
					break;
				}
			break;
		}
	}
	/*
	Views table alter block 2
	*/
	public function viewsTableAlterBlock2(&$vars){
		$Cart = \Drupal::service('Basket')->Cart();
		$vars['header'][] = '';
		foreach ($vars['rows'] as $key => &$line){
			if(empty($line['columns']))						continue;
			if(empty($vars['view']->result[$key]->_entity))	continue;
			// ---
			$CartLine = (object)[
				'nid'			=> $vars['view']->result[$key]->_entity->id(),
				'id'			=> $key
			];
			// ---
			foreach ($line['columns'] as $keyField => &$row){
				switch($keyField){
					case'title':
						$row['content'][0]['field_output'] = [
							'#type'			=> 'inline_template',
							'#template'		=> '<a href="{{ url(\'entity.node.canonical\', {\'node\':entity.id}) }}">{% if image %}{{ basket_image(image, \'thumbnail\') }}{% endif %}  <b>{{ entity.getTitle() }}</a></b>',
							'#context'		=> [
								'image'			=> $Cart->getItemImg($CartLine),
								'entity'		=> $vars['view']->result[$key]->_entity
							]
						];
					break;
				}
			}
			$line['columns'][] = [
				'content'		=> [
					[
						'field_output'	=> [
							'#type'			=> 'inline_template',
							'#template'		=> '<a href="javascript:void(0);" class="form-submit nowrap" onclick="{{onclick}}" data-post="{{post}}">+ {{text}}</a>',
							'#context'		=> [
								'text'			=> self::$Basket->Translate()->t('Add to order'),
								'onclick'		=> 'basket_admin_ajax_link(this, \''.Url::fromRoute('basket.admin.pages', ['page_type' => 'api-orders-addOrderItem'])->toString().'\')',
								'post'			=> json_encode([
									'orderId'		=> self::$Order->id,
									'addItem'		=> [
										'nid'			=> $vars['view']->result[$key]->_entity->id(),
										'params'		=> []
									]
								])
							]
						]
					]
				]
			];
		}
	}
}