<?php

class Brizy_Editor_Compiler {

	const BRIZY_RECOMPILE_TAG_OPTION = 'brizy-recompile-tag';

	/**
	 * @var Brizy_Editor_Project
	 */
	private $project;

	/**
	 * @var Brizy_Admin_Blocks_Manager
	 */
	private $blocksManager;
	/**
	 * @var Brizy_Editor_UrlBuilder
	 */
	private $urlBuilder;
	private $compilerUrl;
	private $compilerDownloadUrl;

	public function __construct(
		Brizy_Editor_Project $project, Brizy_Admin_Blocks_Manager $blocksManager, Brizy_Editor_UrlBuilder $urlBuilder, $compilerUrl, $compilerDownloadUrl
	) {

		$this->project             = $project;
		$this->blocksManager       = $blocksManager;
		$this->urlBuilder          = $urlBuilder;
		$this->compilerUrl         = $compilerUrl;
		$this->compilerDownloadUrl = $compilerDownloadUrl;
	}

	public function compilePost( Brizy_Editor_Post $post, $editorConfig ) {
		$this->urlBuilder->set_post_id( $post->getWpPostId() );
		$editor_data    = $post->getEditorData( true );
		$compilerParam  = $this->compilerParams( $editor_data, $editorConfig );
		$httpClient     = new Brizy_Editor_Http_Client();
		$compilerResult = $httpClient->request( $this->compilerUrl, array( 'body' => $compilerParam ), 'POST' )->get_response_body();
		if ( ! is_array( $compilerResult ) ) {
			throw new UnexpectedValueException( 'The compiler response body is invalid' );
		}
		// process page data
		$pageData = $compilerResult['compiled']['page'];
		// update post
		$this->updatePost( $post, $pageData );
		// update project styles
		if ( isset( $compilerResult['compiled']['project'] ) ) {
			$this->updateProjectStyles( $compilerResult['compiled']['project'] );
		}
		// update global blocks
		if ( isset( $compilerResult['compiled']['globalBlocks'] ) ) {
			$this->updateGlobalBLocks( $compilerResult['compiled']['globalBlocks'] );
		}

		return true;
	}

	public function needsCompile( Brizy_Editor_Post $post ) {

		$currentCompiler = preg_replace( "/((-beta\d+?)?-wp)$/", "", $post->get_compiler_version() );
		$v2              = preg_replace( "/((-beta\d+?)?-wp)$/", "", BRIZY_MINIMUM_COMPILER_VERSION );

		if ( BRIZY_EDITOR_VERSION == 'dev' ) {
			$v2 = BRIZY_EDITOR_VERSION;// force recompile if the post does not have sections
			// usually this will be needed only in dev mode.
			if ( empty( $post->getCompiledSections() ) ) {
				return true;
			}
		}
		if ( version_compare( $currentCompiler, $v2, "<" ) ) {
			return true;
		}

		return false;
	}

	private function updateProjectStyles( $styles ) {
		$this->project->setCompiledStyles( $styles );
		$this->project->set_compiler( Brizy_Editor_Entity::COMPILER_BROWSER );
		$this->project->saveStorage();
	}

	private function updatePost( Brizy_Editor_Post $post, $pageData ) {
		$section_manager = $post->getCompiledSectionManager();
		$section_manager->merge( $pageData, true );
		$post->setCompiledSections( $section_manager->asJson() );
		$post->setCompiledScripts( [] );
		$post->setCompiledStyles( [] );
		$post->set_needs_compile( false );
		$post->set_compiler( Brizy_Editor_Post::COMPILER_BROWSER );
		$post->set_compiler_version( BRIZY_EDITOR_VERSION );
		$post->set_plugin_version( BRIZY_VERSION );
		$post->set_pro_plugin_version( defined( 'BRIZY_PRO_VERSION' ) ? BRIZY_PRO_VERSION : null );
		$post->savePost();
		$post->saveStorage();
	}

	private function updateGlobalBLocks( $globalBlockData ) {
		foreach ( $globalBlockData as $blockData ) {
			$block = $this->blocksManager->getEntity( $blockData['uid'] );
			$this->updatePost( $block, $blockData );
		}
	}

	private function compilerParams( $pageData, $editorConfig ) {

		return apply_filters( 'brizy_compiler_params', array(
			'page_id'      => (int) $editorConfig['wp']['page'],
			'free_version' => BRIZY_EDITOR_VERSION,
			'free_url'     => $this->compilerDownloadUrl,
			'config_json'  => json_encode( $editorConfig ),
		) );
	}

	static public function resetCompiledVersion() {
		global $wpdb;
		$wpdb->query( "UPDATE {$wpdb->postmeta} SET meta_value='0.0.0' WHERE meta_key = '" . Brizy_Editor_Post::BRIZY_POST_COMPILER_VERSION . "'" );
	}

	static public function checkRecompileTag() {
		$currentTag = (int) get_option( self::BRIZY_RECOMPILE_TAG_OPTION, null );
		if ( $currentTag < BRIZY_RECOMPILE_TAG || isset( $_REQUEST['bd_reset_compiled_data'] )) {
			self::resetCompiledVersion();
			update_option( self::BRIZY_RECOMPILE_TAG_OPTION, BRIZY_RECOMPILE_TAG );
		}
	}
}