<?php
namespace ElementorPro\Core\App\Modules\SiteEditor\Data\Endpoints;

use ElementorPro\Plugin;
use Elementor\Core\Utils\Exceptions;
use Elementor\TemplateLibrary\Manager as TemplateManager;
use ElementorPro\Modules\ThemeBuilder\Documents\Theme_Document;
use ElementorPro\Modules\ThemeBuilder\Classes\Conditions_Manager;
use ElementorPro\Modules\ThemeBuilder\Module as ThemeBuilderModule;
use ElementorPro\Modules\ThemeBuilder\Classes\Templates_Types_Manager;
use ElementorPro\Core\App\Modules\SiteEditor\Render_Mode_Template_Preview;
use ElementorPro\Core\App\Modules\SiteEditor\Data\Responses\Lock_Error_Response;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

class Templates extends Base_Endpoint {

	/**
	 * @var TemplateManager
	 */
	private $templates_manager;

	/**
	 * @var array
	 */
	private $document_types;

	public function __construct( $controller ) {
		parent::__construct( $controller );

		$this->templates_manager = Plugin::elementor()->templates_manager;
	}

	/**
	 * @return string
	 */
	public function get_name() {
		return 'templates';
	}

	protected function register() {
		parent::register();

		$this->register_item_route( \WP_REST_Server::DELETABLE );
		$this->register_item_route( \WP_REST_Server::EDITABLE );
		$this->register_items_route( \WP_REST_Server::CREATABLE );
	}

	public function get_items( $request ) {
		$templates = $this->templates_manager->get_source( 'local' )->get_items( [
			'type' => array_keys( $this->get_documents_types() ),
			'post_status' => 'any',
			'orderby' => 'post_date',
			'order' => 'DESC',
		] );

		return $this->normalize_templates_json( $templates );
	}

	public function create_items( $request ) {
		$response = $this->templates_manager->import_template( $request->get_body_params() );

		if ( is_wp_error( $response ) ) {
			return new \WP_Error( 'file', $response->get_error_message(), [ 'status' => Exceptions::BAD_REQUEST ] );
		}

		return $this->normalize_templates_json( $response );
	}

	public function update_item( $id, $request ) {
		$lock_by_user_id = $this->is_post_lock( $id );

		if ( $lock_by_user_id ) {
			return new Lock_Error_Response( $lock_by_user_id );
		}

		wp_update_post( array_merge( [
			'ID' => $id,
		], $request->get_body_params() ) );

		return $this->normalize_template_json_item(
			$this->templates_manager->get_source( 'local' )->get_item( $id )
		);
	}

	public function delete_item( $id, $request ) {
		$lock_by_user_id = $this->is_post_lock( $id );

		if ( $lock_by_user_id ) {
			return new Lock_Error_Response( $lock_by_user_id );
		}

		return ! ! wp_trash_post( $id );
	}

	/**
	 * @return array
	 */
	private function get_documents_types() {
		if ( ! $this->document_types ) {
			/** @var Templates_Types_Manager $types_manager */
			$types_manager = ThemeBuilderModule::instance()->get_types_manager();

			$this->document_types = $types_manager->get_types_config( [
				'support_site_editor' => true,
			] );
		}

		return $this->document_types;
	}

	/**
	 * @param $templates
	 *
	 * @return array
	 */
	private function normalize_templates_json( $templates ) {
		return array_map( [ $this, 'normalize_template_json_item' ], $templates );
	}

	/**
	 * @param $template
	 *
	 * @return array
	 */
	private function normalize_template_json_item( $template ) {
		/** @var Conditions_Manager $conditions_manager */
		$conditions_manager = Plugin::instance()->modules_manager->get_modules( 'theme-builder' )->get_conditions_manager();

		/** @var Theme_Document $document */
		$document = Plugin::elementor()->documents->get( $template['template_id'] );

		$supports_site_editor = $document::get_property( 'support_site_editor' );

		// Supports also a non site editor parts.
		if ( ! $supports_site_editor ) {
			return [
				'id' => $template['template_id'],
				'url' => $template['url'],
				'editURL' => $document->get_edit_url(),
				'supportsSiteEditor' => false,
			];
		}

		$types = $this->get_documents_types();

		$template['instances'] = $conditions_manager->get_document_instances( $template['template_id'] );
		$template['defaultCondition'] = $types[ $template['type'] ]['condition_type'];

		$has_instances = ! empty( $template['instances'] );
		$is_active = false;

		if ( ! $has_instances ) {
			$template['instances'] = [ 'no_instances' => esc_html__( 'No instances', 'elementor-pro' ) ];
		} else {
			$is_active = 'publish' === $template['status'];
		}

		if ( ! $template['thumbnail'] ) {
			$template['thumbnail'] = '';
		}

		$site_editor_config = $document->get_site_editor_config();

		$data = array_merge( $template, [
			'id' => $template['template_id'],
			'exportLink' => $template['export_link'],
			'modifiedDate' => $template['human_modified_date'],
			'editURL' => $document->get_edit_url(),
			'conditions' => array_map( function ( $condition ) {
				return array_merge( $condition, [
					'sub' => $condition['sub_name'],
					'subId' => $condition['sub_id'],
				] );
			}, $conditions_manager->get_document_conditions( $document ) ),
			'isActive' => $is_active,
			'type' => $this->calculate_template_type( $template['type'], $template['instances'] ),
			'previewUrl' => $this->get_preview_url( $template['template_id'] ),
			'placeholderUrl' => $site_editor_config['urls']['thumbnail'],
			'pageLayout' => $site_editor_config['page_layout'],
			'supportsSiteEditor' => true,
		] );

		/**
		 * Template data.
		 *
		 * Filters the data returned by Elementor API as JSON.
		 *
		 * By default Elementor API returns data in a JSON format that enables the
		 * builder to work properly. This hook allows developers to alter the data
		 * returned by the API to add new elements.
		 *
		 * @param array $data Template data.
		 */
		$data = apply_filters( 'elementor-pro/site-editor/data/template', $data );

		return $data;
	}

	/**
	 * @param $type
	 * @param $instances
	 *
	 * @return string
	 */
	private function calculate_template_type( $type, $instances ) {
		$condition_to_type_map = [
			'front_page' => 'single-page',
			'child_of' => 'single-page',
			'page' => 'single-page',
			'not_found404' => 'error-404',
			'search' => 'search-results',
		];

		// "single" type was split into "single-page", "single-post" and "404".
		// this section supports all the old templates that was created as "single".
		if ( 'single' === $type ) {
			// By default show it under single-post.
			$type = 'single-post';

			foreach ( $instances as $condition_name => $condition_label ) {
				if ( isset( $condition_to_type_map[ $condition_name ] ) ) {
					$type = $condition_to_type_map[ $condition_name ];
					break;
				}
			}
		}

		return $type;
	}

	private function get_preview_url( $post_id ) {
		return Render_Mode_Template_Preview::get_url( $post_id );
	}
}
