<?php
/**
 * Manage Symbol
 *
 * @package kirki
 */

namespace Kirki\Ajax;

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

use Kirki\HelperFunctions;


/**
 * Symbol API Class
 */
class Symbol {

	/**
	 * Create/save a symbol
	 *
	 * @return void wp_send_json.
	 * 
	 * @deprecated
	 * @see \Kirki\App\Managers\SymbolManager::save()
	 */
	public static function save() {
		//phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$post_symbol_data = isset( $_POST['data'] ) ? $_POST['data'] : null;
		if ( ! empty( $post_symbol_data ) ) {
			$wp_post = array(
				'post_type' => KIRKI_SYMBOL_TYPE,
			);

			$post_id = wp_insert_post( $wp_post );
			if ( isset( $post_id ) ) {

				$symbol_data = json_decode( stripslashes( $post_symbol_data ), true );
				$symbol_data['data'][ $symbol_data['root'] ]['properties']['symbolId'] = $post_id;

				add_post_meta( $post_id, 'kirki', $symbol_data );
				add_post_meta( $post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE, 'kirki' );

				$data         = array(
					'id'         => $post_id,
					'symbolData' => $symbol_data,
					'type'       => isset( $symbol_data['category'] ) ? $symbol_data['category'] : 'other',
				);
				$data['html'] = self::get_symbol_html_preview( $data );
				wp_send_json( $data );
			}
		};

		die();
	}

	/**
	 * @deprecated
	 * @see \Kirki\App\Managers\SymbolManager::save()
	 */
	public static function save_to_db( $data ) {
		//phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$post_symbol_data = $data ? $data : null;

		if ( ! empty( $post_symbol_data ) ) {
			unset( $post_symbol_data['id'] );
			unset( $post_symbol_data['elementId'] );

			$post_symbol_data = $post_symbol_data['symbolData'];

			$wp_post = array(
				'post_type' => KIRKI_SYMBOL_TYPE,
			);

			$post_id = wp_insert_post( $wp_post );

			if ( isset( $post_id ) ) {

				$symbol_data = $post_symbol_data;
				$symbol_data['data'][ $symbol_data['root'] ]['properties']['symbolId'] = $post_id;

				add_post_meta( $post_id, 'kirki', $symbol_data );
				add_post_meta( $post_id, KIRKI_META_NAME_FOR_POST_EDITOR_MODE, 'kirki' );

				$data         = array(
					'id'         => $post_id,
					'symbolData' => $symbol_data,
					'type'       => isset( $symbol_data['category'] ) ? $symbol_data['category'] : 'other',
				);
				$data['html'] = self::get_symbol_html_preview( $data );

				return $data;
			}
		};

		return null;

	}

	/**
	 * Fetch symbol list
	 * if $internal is true then it will return array
	 * otherwise it will return json for api call
	 *
	 * @param boolean $internal if function call from internally.
	 * @param boolean $html if need html string.
	 * @return array|void wp_send_json.
	 */
	public static function fetch_list( $internal = false, $html = false ) {
		$posts = get_posts(
			array(
				'post_type'   => KIRKI_SYMBOL_TYPE,
				'post_status' => 'draft',
				'numberposts' => -1,
			)
		);

		$symbols = array();

		if ( ! empty( $posts ) ) {
			$symbols = array_map(
				function( $post ) use ( $html, $internal ) {
					 $single_symbol = self::get_single_symbol( $post->ID, true, $html );
					if ( ! $internal ) {
						try {
							unset( $single_symbol['symbolData']['data'] );
							unset( $single_symbol['symbolData']['styleBlocks'] );
						} catch ( \Throwable $th ) {
							// throw $th;
						}
					}
					 return $single_symbol;
				},
				$posts
			);
		}

		if ( $internal ) {
			return $symbols;
		}
		wp_send_json( $symbols );
	}
	/**
	 * Fetch symbol
	 *
	 * @return void wp_send_json.
	 */
	public static function fetch_symbol() {
		$symbol_id           = HelperFunctions::sanitize_text( isset( $_POST['id'] ) ? $_POST['id'] : null );
		$symbol_element_prop = isset( $_POST['symbolElementProp'] ) ? $_POST['symbolElementProp'] : null;
		$collection_item     = isset( $_POST['collectionItem'] ) ? $_POST['collectionItem'] : null;
		$variable_css        = isset( $_POST['variableCSS'] ) ? $_POST['variableCSS'] : true;
		$options             = $collection_item ? json_decode( stripslashes( $collection_item ), true ) : array();
		foreach ( $options as $key => $value ) {
			if ( is_array( $value ) && $key !== 'user' ) {
				$options[ $key ] = json_decode( json_encode( $value ) );
			}
		}
		self::get_single_symbol( $symbol_id, false, true, $symbol_element_prop, $options, $variable_css );
	}


	/**
	 * get single symbol
	 * if $internal is true then it will return array
	 * otherwise it will return json for api call
	 *
	 * @param int     $symbol_id symbol id.
	 * @param boolean $internal if the function call from internally.
	 * @param boolean $html if need html preview string.
	 * @return array|void
	 */
	public static function get_single_symbol( $symbol_id = null, $internal = false, $html = false, $symbol_element_prop = false, $options = array(), $variable_css = true ) {
		//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$symbol_id = $symbol_id ? $symbol_id : HelperFunctions::sanitize_text( isset( $_GET['symbol_id'] ) ? $_GET['symbol_id'] : null );
		$post      = get_post( $symbol_id );
		$symbol    = null;
		if ( $post && $post->post_type == KIRKI_SYMBOL_TYPE ) {
			$symbol               = array();
			$symbol_data          = get_post_meta( $post->ID, 'kirki', true );
			$symbol['id']         = $post->ID;
			$symbol['symbolData'] = $symbol_data;
			$symbol['type']       = isset( $symbol_data['category'] ) ? $symbol_data['category'] : 'other';
			$symbol['setAs']      = isset( $symbol_data['setAs'] ) ? $symbol_data['setAs'] : '';

			if ( ! $internal ) {
				$symbol_element_prop = json_decode( stripslashes( $symbol_element_prop ), true );
			}
			if ( $symbol_element_prop !== false && is_array( $symbol_element_prop ) ) {
				foreach ( $symbol_element_prop as $key => $value ) {
					foreach ( $symbol['symbolData']['data'] as $key2 => $value2 ) {
						if ( isset( $value2['properties']['symbolElPropId'] ) && $value2['properties']['symbolElPropId'] == $key ) {
							if ( isset( $value['contents'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['contents'] = $value['contents'];
							}
							if ( isset( $value['contentElement'] ) ) {
								foreach ( $value['contentElement'] as $new_item ) {
									if ( isset( $new_item['id'] ) ) {
											$symbol['symbolData']['data'][ $new_item['id'] ] = $new_item;
									}
								}
							}
							if ( isset( $value['attributes'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['attributes'] = $value['attributes'];
							}
							if ( isset( $value['wp_attachment_id'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['wp_attachment_id'] = $value['wp_attachment_id'];
							}
							if ( isset( $value['lottie'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['lottie'] = $value['lottie'];
							}
							if ( isset( $value['svgOuterHtml'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['svgOuterHtml'] = $value['svgOuterHtml'];
							}
							if ( isset( $value['tag'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['tag'] = $value['tag'];
							}
							if ( isset( $value['type'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['type'] = $value['type'];
							}
							if ( isset( $value['isActive'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['isActive'] = $value['isActive'];
							}
							if ( isset( $value['preload'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['preload'] = $value['preload'];
							}
							if ( isset( $value['dynamicContent'] ) ) {
								$symbol['symbolData']['data'][ $key2 ]['properties']['dynamicContent'] = $value['dynamicContent'];
							}
							if (
								isset( $symbol['symbolData']['data'][ $key2 ]['properties']['dynamicContent'] ) &&
								$symbol['symbolData']['data'][ $key2 ]['properties']['dynamicContent']['type'] === 'manual'
							) {
								unset( $symbol['symbolData']['data'][ $key2 ]['properties']['dynamicContent'] );
							}
						}
					}
				}
			}

			if ( $html === true ) {
				$symbol['html'] = self::get_symbol_html_preview( $symbol, $options, $variable_css );
			}
		}

		if ( $internal ) {
			return $symbol;
		}
		wp_send_json( $symbol );
	}

	/**
	 * @deprecated
	 * @see \Kirki\App\Managers\SymbolManager::get_preview_html()
	 */
	private static function get_symbol_html_preview( $symbol, $options = array(), $variable_css = true ) {
		if ( ! $symbol['symbolData'] ) {
			return '';
		}
		$symbol_data = $symbol['symbolData'];

		$params = array(
			'blocks'                 => $symbol_data['data'],
			'style_blocks'           => $symbol_data['styleBlocks'],
			'root'                   => $symbol_data['root'],
			'post_id'                => $symbol['id'],
			'options'                => $options,
			'get_style'              => true,
			'get_variable'           => HelperFunctions::isTruthy( $variable_css ),
			'should_take_app_script' => false,
			'prefix'                 => 'kirki-s' . $symbol['id'],
		);

		$s = HelperFunctions::get_html_using_preview_script( $params );
		return $s;
	}

	/**
	 * Update Symbol data
	 *
	 * @return void wp_send_json.
	 */
	public static function update() {
		//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated,WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$symbol_id = HelperFunctions::sanitize_text( isset( $_POST['symbol_id'] ) ? $_POST['symbol_id'] : null );
		//phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$post_symbol_data = isset( $_POST['data'] ) ? $_POST['data'] : null;
		if ( $symbol_id && ! empty( $post_symbol_data ) ) {
			$data        = json_decode( stripslashes( $post_symbol_data ), true );
			$symbol_data = get_post_meta( $symbol_id, 'kirki', true );

			if ( $symbol_data ) {
				if ( isset( $data['data'] ) ) {
					$symbol_data['data'] = $data['data'];
				}
				if ( isset( $data['styleBlocks'] ) ) {
					$symbol_data['styleBlocks'] = $data['styleBlocks'];
				}
				if ( isset( $data['customFonts'] ) ) {
					$symbol_data['customFonts'] = $data['customFonts'];
				}
				if ( isset( $data['name'] ) ) {
					$symbol_data['name'] = $data['name'];
				}
				if ( isset( $data['category'] ) ) {
					$symbol_data['category'] = $data['category'];
				}
				if ( isset( $data['root'] ) ) {
					$symbol_data['root'] = $data['root'];
				}
				// if ( isset( $data['conditions'] ) ) {
				// $symbol_data['conditions'] = $data['conditions'];
				// }

				$set_as_toggle_success = true;
				if ( isset( $data['setAs'] ) ) {
					$symbol_data['setAs'] = $data['setAs'];

					if ( $data['setAs'] != '' ) {
						$all_symbol = self::fetch_list( true );
						foreach ( $all_symbol as $key => $value ) {
							if ( $value['id'] != $symbol_id && isset( $value['symbolData'], $value['symbolData']['setAs'] ) && $value['symbolData']['setAs'] == $data['setAs'] ) {
								$all_symbol[ $key ]['symbolData']['setAs'] = '';
								$set_as_toggle_success                     = update_post_meta( $value['id'], 'kirki', $all_symbol[ $key ]['symbolData'] );
							}
						}
					}
				}

				if ( $set_as_toggle_success !== true ) {
					wp_send_json( false );
				}

				$updated = update_post_meta( $symbol_id, 'kirki', $symbol_data );

				$updated === true && $set_as_toggle_success === true ? wp_send_json( self::get_single_symbol( $symbol_id, true, true ) ) : wp_send_json( false );
			} else {
				wp_send_json( false );
			}
		}
		die();
	}

	/**
	 * Delete a symbol
	 *
	 * @return void
	 */
	public static function delete() {
		//phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$symbol_id = HelperFunctions::sanitize_text( isset( $_POST['symbol_id'] ) ? $_POST['symbol_id'] : null );
		if ( $symbol_id ) {
			$post = wp_delete_post( $symbol_id );
			isset( $post ) ? wp_send_json( true ) : wp_send_json( false );
		}
		die();
	}

	public static function get_pre_built_html_using_url() {
		 $raw_url = isset( $_GET['elementUrl'] ) ? wp_unslash( $_GET['elementUrl'] ) : '';

    if ( empty( $raw_url ) ) {
        wp_send_json_error( 'Missing elementUrl', 400 );
    }
		$allowed_host = wp_parse_url( home_url(), PHP_URL_HOST );
    $requested    = wp_parse_url( $raw_url );

    if (
			! $requested ||
			empty( $requested['host'] ) ||
			strtolower( $requested['host'] ) !== strtolower( $allowed_host )
    ) {
        wp_send_json_error( 'URL not permitted', 403 );
    }

		$resolved_ip = gethostbyname( $requested['host'] );

		if ( self::is_private_or_loopback_ip( $resolved_ip ) ) {
      wp_send_json_error( 'URL not permitted', 403 );
    }

		$safe_url = self::rebuild_url( $requested );

		$response = HelperFunctions::http_get( $safe_url, array(
			'timeout'   => 30,
			'sslverify' => false,   
			'redirection' => 0,  
    ));

		if ( is_wp_error( $response ) ) {
      wp_send_json_error( 'Request failed', 502 );
    }

		$body = wp_remote_retrieve_body( $response );
    $data = json_decode( $body, true );


		$params = array(
			'blocks'                 => $data['blocks'],
			'style_blocks'           => $data['styles'],
			'root'                   => $data['root'],
			'post_id'                => false,
			'options'                => array(),
			'get_style'              => true,
			'get_variable'           => false,
			'should_take_app_script' => false,
		);

		$html = HelperFunctions::get_html_using_preview_script( $params );

		wp_send_json_success( $html );
	}

	/**
 	* Returns true for any IP that should never be reached from a server-side fetch.
 	* Covers loopback, RFC 1918, link-local (APIPA / cloud metadata), and IPv6 equivalents.
 	*/
	private static function is_private_or_loopback_ip( string $ip ): bool {
		if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
			return true;
		}

		return ! filter_var(
			$ip,
			FILTER_VALIDATE_IP,
			FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
		);
	}


	/**
	 * Reconstructs a URL from wp_parse_url parts so the raw user string
	 * is never passed directly to the HTTP client.
	 */
	private static function rebuild_url( array $parts ): string {
		$scheme = isset( $parts['scheme'] ) && strtolower( $parts['scheme'] ) === 'https' ? 'https' : 'https';
		$host   = $parts['host'];
		$path   = isset( $parts['path'] ) ? $parts['path'] : '/';
		$query  = isset( $parts['query'] ) ? '?' . $parts['query'] : '';

		return "{$scheme}://{$host}{$path}{$query}";
	}
}
