<?php
/**
 * Signature field class for SureForms
 *
 * @package sureforms.
 * @since 1.6.0
 */

namespace SRFM_Pro\Inc\Pro\Signature;

use SRFM\Inc\Helper;
use SRFM_Pro\Inc\Helper as Pro_Helper;
use SRFM_Pro\Inc\Traits\Get_Instance;

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

/**
 * Signature field class for SureForms
 *
 * @since 1.6.0
 */
class Init {
	use Get_Instance;

	/**
	 * Associative array to keep the count of block that requires scripts to work.
	 *
	 * @var array<int>
	 * @since 1.6.0
	 */
	public static $script_dep_blocks = [
		'signature' => 0,
	];

	/**
	 * Constructor
	 *
	 * @since 1.6.0
	 * @return void
	 */
	public function __construct() {
		add_filter( 'srfm_register_additional_blocks', [ $this, 'register_field' ] );
		add_action( 'enqueue_block_editor_assets', [ $this, 'enqueue_admin_scripts' ] );
		add_filter( 'render_block', [ $this, 'generate_render_script' ], 10, 2 );
		add_filter( 'srfm_css_vars_sizes', [ $this, 'cf_spacing_variables' ] );
		add_filter( 'srfm_dynamic_validation_messages', [ $this, 'add_signature_messages' ] );
		add_filter( 'srfm_general_dynamic_options_to_save', [ $this, 'add_signature_validation_messages_to_save' ], 10, 2 );
		add_filter( 'srfm_allowed_block_types', [ $this, 'allow_signature_block_in_sureforms' ], 10, 1 );
		add_filter( 'srfm_default_dynamic_block_option', [ $this, 'add_signature_default_dynamic_pro_block_values' ], 10, 2 );
		add_filter( 'srfm_before_prepare_submission_data', [ $this, 'store_signature_as_image' ] );
		add_filter( 'srfm_blocks', [ $this, 'allow_signature_block_in_sureforms' ] );
		add_action( 'srfm_enqueue_common_field_assets', [ $this, 'get_signature_assets' ] );
		add_filter( 'srfm_pro_updater_callbacks', [ $this, 'add_signature_dynamic_option_callback' ] );
		add_action( 'srfm_pro_before_deleting_entry', [ $this, 'delete_signature_files_on_entry_deletion' ] );
		add_filter( 'srfm_entry_render_field_custom_value', [ $this, 'is_signature_field' ], 10, 2 );
		add_filter( 'srfm_entry_custom_value', [ $this, 'show_signature_value_in_entry' ], 10, 2 );
		add_filter( 'srfm_smart_tag_view_link', [ $this, 'render_signature_image' ], 10, 2 );
		add_filter( 'srfm_email_template_render_url', [ $this, 'render_signature_image' ], 10, 2 );
	}

	/**
	 * Render signature as image form smart tag or email template.
	 * Instead of returning the view link, it returns an image link if the field is a signature field.
	 *
	 * @param string $view_link The view link.
	 * @param array  $args Arguments passed to the filter.
	 *
	 * @return string|false
	 * @since 1.10.1
	 */
	public function render_signature_image( $view_link, $args ) {
		// return an image link if the field is a signature field.
		if (
			isset( $args['block_type'] )
			&& strpos( $args['block_type'], 'srfm-signature' ) !== false
			&& ! empty( $args['submission_item_value'] )
		) {
			$url = wp_http_validate_url( (string) $args['submission_item_value'] );
			if ( $url ) {
				ob_start();
				?>
					<a target="_blank"
					href="<?php echo esc_url( $url ); ?>"
				style="outline: none;"
				rel="noopener noreferrer"
				title="<?php echo esc_attr__( 'Opens signature image in a new window', 'sureforms-pro' ); ?>">
					<img src="<?php echo esc_url( $url ); ?>" alt="<?php echo esc_attr__( 'Signature Image', 'sureforms-pro' ); ?>" width="70%" />
				</a>
				<?php
				return ob_get_clean();
			}
		}
		return $view_link;
	}

	/**
	 * Check if the field is a signature field.
	 *
	 * @param bool   $value initial value of the filter.
	 * @param string $field_name Field name.
	 *
	 * @since 1.6.0
	 * @return bool
	 */
	public function is_signature_field( $value, $field_name ) {
		if ( false !== strpos( $field_name, 'srfm-signature' ) ) {
			$value = true;
		}

		return $value;
	}

	/**
	 * Show signature value in entry.
	 *
	 * @param string $content Content.
	 * @param string $value Field value.
	 *
	 * @since 1.6.0
	 * @return string|void
	 */
	public function show_signature_value_in_entry( $content, $value ) {

		ob_start();
		?>

		<td>
			<div class="file-cards-container">
				<?php
				$file_url = urldecode( Helper::get_string_value( $value ) );

				if ( ! empty( $file_url ) ) {
					$file_path = Helper::convert_fileurl_to_filepath( $file_url );

					if ( ! file_exists( $file_path ) ) {
						return;
					}

					$file_type = pathinfo( $file_url, PATHINFO_EXTENSION );
					$is_image  = in_array( strtolower( $file_type ), [ 'gif', 'png', 'bmp', 'jpg', 'jpeg', 'svg' ], true );
					?>
					<div class="file-card" data-fileurl-hash="<?php echo esc_attr( md5( $file_url ) ); ?>">
						<?php if ( $is_image ) { ?>
							<div class="file-card-image">
								<a target="_blank" href="<?php echo esc_attr( $file_url ); ?>">
									<img src="<?php echo esc_attr( $file_url ); ?>" alt="<?php esc_attr_e( 'Image', 'sureforms-pro' ); ?>" />
								</a>
							</div>
						<?php } ?>
						<div class="file-card-url">
							<a target="_blank" href="<?php echo esc_attr( $file_url ); ?>"><?php echo esc_html__( 'Open', 'sureforms-pro' ); ?></a>
						</div>
					</div>
				<?php } ?>
			</div>
		</td>
		<?php
		$output = ob_get_clean();

		$content .= $output;

		return $content;
	}

	/**
	 * Delete signature files on entry deletion.
	 *
	 * @param array<mixed> $entry_data Entry data.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	public function delete_signature_files_on_entry_deletion( $entry_data ) {
		if ( empty( $entry_data ) || ! is_array( $entry_data ) ) {
			return;
		}

		// Get the form data.
		if ( empty( $entry_data['form_data'] ) || ! is_array( $entry_data['form_data'] ) ) {
			return;
		}

		// delete signature files.
		foreach ( $entry_data['form_data'] as $field_name => $value ) {
			// Continue to the next iteration if the field name does not contain 'srfm-signature' and value is not an array.
			if ( false === strpos( $field_name, 'srfm-signature' ) && ! is_string( $value ) ) {
				continue;
			}
				// If the file URL is empty, skip to the next iteration.
			if ( empty( $value ) ) {
				continue;
			}

			// Delete signature file from the uploads directory.
			Pro_Helper::delete_upload_file_from_subdir( $value, 'sureforms/signature/' );
		}
	}

	/**
	 * Add signature field dynamic option callback.
	 *
	 * @param array<string> $callbacks Array of callbacks.
	 *
	 * @since 1.6.0
	 * @return array<mixed>
	 */
	public function add_signature_dynamic_option_callback( $callbacks ) {
		$callbacks['1.6.0'] = [ 'SRFM_Pro\Inc\Pro\Signature\Init::add_signature_default_dynamic_options' ];
		return $callbacks;
	}

	/**
	 * Add signature field dynamic option callback.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	public static function add_signature_default_dynamic_options() {
		$previous_options = get_option( 'srfm_default_dynamic_block_option' );

		if ( ! empty( $previous_options ) && is_array( $previous_options ) ) {
			$required_message = Helper::get_common_err_msg();
			$current_options  = self::add_signature_messages();
			$current_options  = self::add_signature_default_dynamic_pro_block_values( $current_options, $required_message );

			// Iterate $current_options and update the options.
			foreach ( $current_options as $key => $value ) {
				if ( ! isset( $previous_options[ $key ] ) ) {
					$previous_options[ $key ] = $value;
				}
			}
			update_option( 'srfm_default_dynamic_block_option', $previous_options );
		}
	}

	/**
	 * Store signature as image.
	 *
	 * @param array<mixed> $submission_data submission data.
	 *
	 * @return array<mixed>
	 * @since 1.6.0
	 */
	public function store_signature_as_image( $submission_data ) {
		global $wp_filesystem;
		$upload_dir = wp_upload_dir();
		$tmp_dir    = $upload_dir['basedir'] . '/sureforms/tmp/';
		$directory  = $upload_dir['basedir'] . '/sureforms/signature/';

		if ( ! file_exists( $tmp_dir ) ) {
			mkdir( $tmp_dir, 0755, true );
		}

		// Ensure directory exists.
		if ( ! file_exists( $directory ) ) {
			mkdir( $directory, 0755, true );
		}

		foreach ( $submission_data as $key => $value ) {
			if ( strpos( $key, 'srfm-signature' ) === false ) {
				continue;
			}

			// if value does not contain data:image/ then for now skip to the next iteration.
			if ( strpos( Helper::get_string_value( $value ), 'data:image/' ) === false ) {
				continue;
			}

			// Decode base64 image data.
			$image_data = base64_decode( Helper::get_string_value( preg_replace( '#^data:image/\w+;base64,#i', '', Helper::get_string_value( $value ) ) ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- Base64 decode is required here to decode the image data.
			if ( ! $image_data ) {
				continue;
			}

			$filename  = 'srfm-signature-' . uniqid() . '.png';
			$file_path = $tmp_dir . $filename;

			// Save the image file.
			if ( ! function_exists( 'WP_Filesystem' ) ) {
				require_once ABSPATH . 'wp-admin/includes/file.php';
			}
			WP_Filesystem();
			$wp_filesystem->put_contents( $file_path, $image_data, FS_CHMOD_FILE );

			$check_file = wp_check_filetype_and_ext( $file_path, $filename, null );

			// Check if the file is an image.
			if ( ! $check_file['type'] || strpos( $check_file['type'], 'image' ) === false ) {
				unlink( $file_path );
				continue;
			}

			$temp_dile_path = $file_path;

			// Move the file to the final directory.
			rename( $file_path, $directory . $filename );

			// Remove the file from the tmp directory.
			if ( file_exists( $temp_dile_path ) ) {
				unlink( $temp_dile_path );
			}

			// Replace base64 data with file path.
			$submission_data[ $key ] = $this->get_file_url( $file_path );
		}

		return $submission_data;
	}

	/**
	 * Get file URL.
	 *
	 * @param string $file_path File path.
	 *
	 * @return string
	 * @since 1.6.0
	 */
	public function get_file_url( $file_path ) {
		$upload_dir = wp_upload_dir();
		$upload_url = $upload_dir['baseurl'] . '/sureforms/signature/';
		$file_name  = basename( $file_path );
		return $upload_url . $file_name;
	}

	/**
	 * Add pro block's default error message values.
	 *
	 * @param array<mixed> $default_values the default values.
	 * @param array<mixed> $common_err_msg the common error message.
	 * @since 1.6.0
	 * @return array<mixed>
	 */
	public static function add_signature_default_dynamic_pro_block_values( $default_values, $common_err_msg ) {

		$default_pro_values = [
			'srfm_signature_block_required_text'    => $common_err_msg['required'],
			/* translators: %s represents the maximum file size allowed in MB */
			'srfm_signature_block_size_exceed'      => __( 'File size should not exceed %s MB.', 'sureforms-pro' ),
			'srfm_signature_block_type_not_allowed' => __( 'File type not allowed.', 'sureforms-pro' ),
			'srfm_signature_block_invalid_value'    => __( 'Please enter a valid signature!', 'sureforms-pro' ),
		];

		return array_merge( $default_values, $default_pro_values );
	}

	/**
	 * Allow signature block in sureforms.
	 *
	 * @param array<string> $blocks Array of blocks.
	 *
	 * @since 1.6.0
	 * @return array<string>
	 */
	public function allow_signature_block_in_sureforms( $blocks ) {
		return array_merge(
			$blocks,
			[
				'srfm/signature',
			]
		);
	}

	/**
	 * Add signature field messages.
	 *
	 * @param array<string> $default_options Default options.
	 * @param array<string> $setting_options Setting options.
	 *
	 * @since 1.6.0
	 * @return array<string>
	 */
	public function add_signature_validation_messages_to_save( $default_options, $setting_options ) {
		$pro_options_keys    = [
			'srfm_signature_block_required_text',
			'srfm_signature_block_size_exceed',
			'srfm_signature_block_type_not_allowed',
			'srfm_signature_block_invalid_value',
		];
		$pro_options_to_save = [];
		foreach ( $pro_options_keys as $key ) {
			if ( isset( $setting_options[ $key ] ) ) {
				$pro_options_to_save[ $key ] = $setting_options[ $key ];
			}
		}
		return array_merge( $default_options, $pro_options_to_save );
	}

	/**
	 * Retrieve default dynamic validation messages.
	 *
	 * @param array<string, string> $default_value Associative array of translated validation messages for frontend use.
	 * @since 1.6.0
	 * @return array Associative array of translated validation messages for frontend use.
	 */
	public static function add_signature_messages( $default_value = [] ) {
		$translatable_array = [
			'srfm_signature_block_required_text'    => __( 'This field is required.', 'sureforms-pro' ),
			/* translators: %s represents the maximum file size allowed in MB */
			'srfm_signature_block_size_exceed'      => __( 'File size should not exceed %s MB.', 'sureforms-pro' ),
			'srfm_signature_block_type_not_allowed' => __( 'File type not allowed.', 'sureforms-pro' ),
			'srfm_signature_block_invalid_value'    => __( 'Please enter a valid signature value!', 'sureforms-pro' ),
		];

		return ! empty( $default_value ) && is_array( $default_value ) ? array_merge( $default_value, $translatable_array ) : $translatable_array;
	}

	/**
	 * Render function.
	 *
	 * @param string $block_content Entire Block Content.
	 * @param array  $block Block Properties As An Array.
	 * @since 1.6.0
	 * @return string
	 */
	public function generate_render_script( $block_content, $block ) {
		if ( isset( $block['blockName'] ) && 'srfm/signature' === $block['blockName'] ) {
			self::enqueue_frontend_assets( $block['blockName'] );
		}
		return $block_content;
	}

	/**
	 * Enqueue required styles for the signature field in the editor and frontend.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	public function enqueue_styles() {
		$file_prefix = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? '' : '.min';
		$dir_name    = defined( 'SRFM_DEBUG' ) && SRFM_DEBUG ? 'unminified' : 'minified';
		$css_uri     = SRFM_PRO_URL . 'assets/css/' . $dir_name . '/package/pro/';
		// This checks the text direction of the site, if it is RTL then it will load the RTL version of the CSS file.
		$rtl = is_rtl() ? '-rtl' : '';

		// Load the frontend custom app styles.
		wp_enqueue_style( SRFM_PRO_SLUG . '-signature', $css_uri . 'signature' . $file_prefix . $rtl . '.css', [], SRFM_PRO_VER );
	}

	/**
	 * Register signature field.
	 *
	 * @param array<mixed> $blocks Array of blocks.
	 *
	 * @since 1.6.0
	 * @return array<mixed>
	 */
	public function register_field( $blocks ) {
		$blocks[] = [
			'dir'       => SRFM_PRO_DIR . 'inc/pro/signature/block.php',
			'namespace' => 'SRFM_PRO\\Inc\\Blocks',
		];

		return $blocks;
	}

	/**
	 * Enqueue signature form admin scripts.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	public function enqueue_admin_scripts() {
		$this->enqueue_styles();
		$scripts = [
			[
				'unique_file'        => 'signatureAdmin',
				'unique_handle'      => 'signature-admin',
				'extra_dependencies' => [ 'srfm-blocks', SRFM_PRO_SLUG . '-block-editor' ],
			],
		];
		$this->enqueue_scripts( $scripts );
	}

	/**
	 * Enqueue signature form frontend scripts.
	 *
	 * @param string $block_type Block type.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	public function enqueue_frontend_assets( $block_type = '' ) {
		$block_name = str_replace( 'srfm/', '', $block_type );

		// Check if block is in the array and check if block is already enqueued.
		if (
			in_array( $block_name, array_keys( self::$script_dep_blocks ), true ) &&
			0 === self::$script_dep_blocks[ $block_name ]
		) {
			self::$script_dep_blocks[ $block_name ] += 1;
			$this->get_signature_assets();
		}
	}

	/**
	 * Get signature assets.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	public function get_signature_assets() {
		$this->enqueue_styles();
		// enqueue signature pad library.
		wp_enqueue_script( 'srfm-pro-signature-pad-lib', SRFM_PRO_URL . 'assets/js/minified/deps/signature_pad.umd.min.js', [], SRFM_PRO_VER, true );
		$scripts = [
			[
				'unique_file'        => 'signatureFrontend',
				'unique_handle'      => 'signature-frontend',
				'extra_dependencies' => [ 'srfm-pro-signature-pad-lib' ],
			],
		];
		$this->enqueue_scripts( $scripts );
	}

	/**
	 * Replace the spacing variables with values for the signature block.
	 * This is used in the frontend.
	 *
	 * @param array<string|mixed> $sizes array of css variables coming from 'srfm_css_vars_sizes' filter.
	 * @since 1.6.0
	 * @return array<string|mixed>
	 */
	public function cf_spacing_variables( $sizes ) {
		return array_replace_recursive(
			$sizes,
			[
				'small'  => [
					'--srfm-signature-canvas-height' => '120px',
					'--srfm-signature-button-bottom' => '12px',
				],
				'medium' => [
					'--srfm-signature-canvas-height' => '140px',
					'--srfm-signature-button-bottom' => '14px',
				],
				'large'  => [
					'--srfm-signature-canvas-height' => '160px',
					'--srfm-signature-button-bottom' => '16px',
				],
			]
		);
	}

	/**
	 * Enqueue scripts.
	 *
	 * @param array<array<string, mixed>> $scripts Array of scripts to enqueue.
	 *
	 * @since 1.6.0
	 * @return void
	 */
	private function enqueue_scripts( $scripts ) {
		foreach ( $scripts as $script ) {
			$script_dep_path = SRFM_PRO_DIR . 'dist/package/pro/' . $script['unique_file'] . '.asset.php';
			$script_dep_data = file_exists( $script_dep_path )
				? include $script_dep_path
				: [
					'dependencies' => [],
					'version'      => SRFM_PRO_VER,
				];

			// Ensure dependencies are arrays.
			$script_dep = array_merge(
				is_array( $script_dep_data['dependencies'] ) ? $script_dep_data['dependencies'] : [],
				is_array( $script['extra_dependencies'] ) ? $script['extra_dependencies'] : []
			);

			// Enqueue script.
			wp_enqueue_script(
				SRFM_PRO_SLUG . '-' . $script['unique_handle'], // Handle.
				SRFM_PRO_URL . 'dist/package/pro/' . $script['unique_file'] . '.js',
				$script_dep, // Dependencies.
				$script_dep_data['version'], // Version.
				true // Enqueue the script in the footer.
			);

			// Register script translations.
			Pro_Helper::register_script_translations( SRFM_PRO_SLUG . '-' . $script['unique_handle'] );
		}
	}

}
