<?php

namespace Elementor\Core\Responsive\Files;

use Elementor\Core\Breakpoints\Breakpoint;
use Elementor\Core\Files\Base;
use Elementor\Core\Responsive\Responsive;
use Elementor\Plugin;

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

class Frontend extends Base {

	const META_KEY = 'elementor-custom-breakpoints-files';

	private $template_file;

	/**
	 * @since 2.1.0
	 * @access public
	 */
	public function __construct( $file_name, $template_file = null ) {
		$this->template_file = $template_file;

		parent::__construct( $file_name );
	}

	/**
	 * @since 2.1.0
	 * @access public
	 */
	public function parse_content() {
		$breakpoints = Plugin::$instance->breakpoints->get_active_breakpoints();

		$breakpoints_keys = array_keys( $breakpoints );

		$file_content = file_get_contents( $this->template_file );

		// The regex pattern parses placeholders located in the frontend _templates.scss file.
		$file_content = preg_replace_callback( '/ELEMENTOR_SCREEN_([A-Z_]+)(?:_(MIN|MAX|NEXT))/', function ( $placeholder_data ) use ( $breakpoints_keys, $breakpoints ) {
			// Handle BC for legacy template files and Elementor Pro builds.
			$placeholder_data = $this->maybe_convert_placeholder_data( $placeholder_data );

			$breakpoint_index = array_search( strtolower( $placeholder_data[1] ), $breakpoints_keys, true );

			if ( 'DESKTOP' === $placeholder_data[1] ) {
				if ( 'MIN' === $placeholder_data[2] ) {
					$value = Plugin::$instance->breakpoints->get_desktop_min_point();
				} elseif ( isset( $breakpoints['widescreen'] ) ) {
					// If the 'widescreen' breakpoint is active, the Desktop's max value is the Widescreen breakpoint - 1px.
					$value = $breakpoints['widescreen']->get_value() - 1;
				} else {
					// If the 'widescreen' breakpoint is not active, the Desktop device should not have a max value.
					$value = 99999;
				}
			} elseif ( false === $breakpoint_index ) {
				// If the breakpoint in the placeholder is not active - use a -1 value for the media query, to make
				// sure the setting is printed (to avoid a PHP error) but doesn't apply.
				$value = -1;
			} elseif ( 'WIDESCREEN' === $placeholder_data[1] ) {
				$value = $breakpoints['widescreen']->get_value();
			} else {
				$breakpoint_index = array_search( strtolower( $placeholder_data[1] ), $breakpoints_keys, true );

				$is_max_point = 'MAX' === $placeholder_data[2];

				// If the placeholder capture is `MOBILE_NEXT` or `TABLET_NEXT`, the original breakpoint value is used.
				if ( ! $is_max_point && 'NEXT' !== $placeholder_data[2] ) {
					$breakpoint_index--;
				}

				$value = $breakpoints[ $breakpoints_keys[ $breakpoint_index ] ]->get_value();

				if ( ! $is_max_point ) {
					$value++;
				}
			}

			return $value . 'px';
		}, $file_content );

		return $file_content;
	}

	/**
	 * Load meta.
	 *
	 * Retrieve the file meta data.
	 *
	 * @since 2.1.0
	 * @access protected
	 */
	protected function load_meta() {
		$option = $this->load_meta_option();

		$file_meta_key = $this->get_file_meta_key();

		if ( empty( $option[ $file_meta_key ] ) ) {
			return [];
		}

		return $option[ $file_meta_key ];
	}

	/**
	 * Update meta.
	 *
	 * Update the file meta data.
	 *
	 * @since 2.1.0
	 * @access protected
	 *
	 * @param array $meta New meta data.
	 */
	protected function update_meta( $meta ) {
		$option = $this->load_meta_option();

		$option[ $this->get_file_meta_key() ] = $meta;

		update_option( static::META_KEY, $option );
	}

	/**
	 * Delete meta.
	 *
	 * Delete the file meta data.
	 *
	 * @since 2.1.0
	 * @access protected
	 */
	protected function delete_meta() {
		$option = $this->load_meta_option();

		$file_meta_key = $this->get_file_meta_key();

		if ( isset( $option[ $file_meta_key ] ) ) {
			unset( $option[ $file_meta_key ] );
		}

		if ( $option ) {
			update_option( static::META_KEY, $option );
		} else {
			delete_option( static::META_KEY );
		}
	}

	/**
	 * @since 2.1.0
	 * @access private
	 */
	private function get_file_meta_key() {
		return pathinfo( $this->get_file_name(), PATHINFO_FILENAME );
	}

	/**
	 * @since 2.1.0
	 * @access private
	 */
	private function load_meta_option() {
		$option = get_option( static::META_KEY );

		if ( ! $option ) {
			$option = [];
		}

		return $option;
	}

	/**
	 * Maybe Convert Placeholder Data
	 *
	 * Converts responsive placeholders in Elementor CSS template files from the legacy format into the new format.
	 * Used for backwards compatibility for old Pro versions that were built with an Elementor Core version <3.2.0.
	 *
	 * @since 3.2.3
	 *
	 * @param $placeholder_data
	 * @return mixed
	 */
	private function maybe_convert_placeholder_data( $placeholder_data ) {
		switch ( $placeholder_data[1] ) {
			case 'SM':
				$placeholder_data[1] = 'MOBILE';
				break;
			case 'MD':
				$placeholder_data[1] = 'TABLET';
				break;
			case 'LG':
				$placeholder_data[1] = 'DESKTOP';
		}

		return $placeholder_data;
	}
}
