<?php

namespace GravityKit\GravityExport\Exporting;

use GFExcel\Values\StringValue;
use GFExcel\Vendor\PhpOffice\PhpSpreadsheet\Cell\Cell;
use GFExcel\Vendor\PhpOffice\PhpSpreadsheet\Exception;
use GFExcel\Vendor\PhpOffice\PhpSpreadsheet\Helper\Html as HtmlHelper;
use GFExcel\Vendor\PhpOffice\PhpSpreadsheet\RichText\RichText;
use GravityKit\GravityExport\Feature;

/**
 * Shows inline HTML in columns in Xlsx (Excel) and PDF.
 * @since $ver$
 */
final class ExportAsHtml extends Feature {
	/**
	 * The name of the setting.
	 * @since $ver$
	 */
	private const SETTING_SHOW_HTML = 'show-html';

	/**
	 * The html helper.
	 * @since $ver$
	 * @var HtmlHelper
	 */
	private $html_helper;

	/**
	 * Micro cache for quicker lookups.
	 * @since $ver$
	 * @var array
	 */
	private $micro_cache = [];

	/**
	 * @inheritDoc
	 * @since $ver$
	 */
	protected function init(): void {
		add_filter( 'gk/gravityexport/settings/sections', \Closure::fromCallable( [ $this, 'add_settings' ] ), 10, 2 );
		add_filter( 'gfexcel_renderer_cell_properties', \Closure::fromCallable( [ $this, 'replace_html_content'	] ), 10, 3 );

		$this->html_helper  = new HtmlHelper();
	}


	/**
	 * Whether HTML should be shown in the export.
	 * @since $ver$
	 *
	 * @param int $form_id The form id.
	 * @param string $field_id The field id.
	 *
	 * @return bool Whether to shown HTML in the export.
	 */
	private function should_show_html( int $form_id, string $field_id ): bool {
		if ( isset( $this->micro_cache[ $form_id ][ $field_id ] ) ) {
			return $this->micro_cache[ $form_id ][ $field_id ];
		}

		return $this->micro_cache[ $form_id ][ $field_id ] = (bool) gf_apply_filters(
			[ 'gk/gravityexport/feature/show-html', $form_id, $field_id ],
			(bool) ( $this->addon->get_plugin_setting( self::SETTING_SHOW_HTML ) ?: false ),
			$form_id,
			$field_id
		);
	}

	/**
	 * Whether the provided content contains HTML.
	 * @since $ver$
	 *
	 * @param string $content The content.
	 *
	 * @return bool
	 */
	private function contains_html( string $content ): bool {
		return strip_tags( $content ) !== $content;
	}

	/**
	 * Replaces the content of a cell with HTML enabled content.
	 * @since $ver$
	 *
	 * @param Cell $cell The cell.
	 * @param mixed $value The value.
	 * @param int $form_id The form id.
	 */
	private function replace_html_content( Cell $cell, $value, $form_id ): void {
		if (
			! $value instanceof StringValue
			|| ! $this->should_show_html( (int) $form_id, $value->getFieldId() )
			|| ! $this->contains_html( $value->getValue() )
		) {
			return;
		}

		$html = $this->html_helper->toRichTextObject( nl2br( $value->getValue() ) );
		$this->reset_html_font($html);

		try {
			$cell->setValue( $html );
		} catch ( Exception $e ) {
			$this->addon->logger->error('The content could not be converted to HTML.');
		}
	}

	/**
	 * Fixes the font family and size for HTML parsing.
	 * @since $ver$
	 *
	 * @param RichText $html The rich text object.
	 */
	private function reset_html_font( RichText $html ): void {
		foreach ( $html->getRichTextElements() as $element ) {
			$element->getFont()
			        ->setName( 'Arial' )
			        ->setSize( 10 );
		}
	}

	/**
	 * Adds the settings for the appropriate section.
	 * @since $ver$
	 *
	 * @param array $sections The original sections.
	 *
	 * @return array The updated sections.
	 */
	private function add_settings( array $sections ): array {
		foreach ( $sections as $i => $section ) {
			if ( 'general-section' !== ( $section['id'] ?? null ) ) {
				continue;
			}

			$sections[ $i ]['settings'][] = [
				'title'       => esc_html__( 'Show basic HTML on export', 'gk-gravityexport' ),
				'name'        => self::SETTING_SHOW_HTML,
				'id'          => self::SETTING_SHOW_HTML,
				'value'       => $this->addon->get_plugin_setting( self::SETTING_SHOW_HTML ),
				'description' => __( 'Display HTML from a Paragraph Text field in the export, like <strong>Bold</strong> and <em>Italic</em>.', 'gk-gravityexport' ),
				'type'        => 'checkbox',
			];
		}

		return $sections;
	}
}
