<?php
defined( 'ABSPATH' ) || exit;

/**
 * Split Text — text whose characters/words/lines/paragraphs animate in sequence.
 *
 * The server renders the REAL text inside the chosen tag. Splitting happens
 * client-side in initSplitText() (assets/js/jalpi-frontend.js), which means the
 * text is crawlable, selectable, and fully readable when JS is unavailable or
 * the visitor has asked for reduced motion.
 */
class Jalpi_Element_Split_Text extends Jalpi_Element {

	use Jalpi_Split_Text;

	public static function type(): string {
		return 'split-text';
	}

	public function render( array $node, Jalpi_Renderer $renderer ): string {
		$id       = sanitize_html_class( $node['id'] ?? '' );
		$content  = $node['content']  ?? [];
		$styles   = $node['styles']   ?? [];
		$settings = $node['settings'] ?? [];

		$text = wp_kses_post(
			$renderer->tags( $renderer->get_current_post_id() )->resolve( $content['text'] ?? '' )
		);

		$allowed_tags = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'span' ];
		$tag          = in_array( $content['tag'] ?? 'h2', $allowed_tags, true ) ? $content['tag'] : 'h2';

		$a   = $renderer->get_css_attrs( $node );
		$sel = '.jalpi-el.jalpi-' . $id;

		$css  = "{$sel}{display:block;box-sizing:border-box;";
		$css .= $renderer->styles_to_css( $styles );
		$css .= '}';

		// Per-state and per-piece styling. Applied to the pieces themselves so
		// they win over the element-level typography.
		$piece = [];

		if ( ! empty( $styles['letterSpacing'] ) ) {
			$ls = sanitize_text_field( $styles['letterSpacing'] );
			if ( $ls ) {
				$piece[] = 'letter-spacing:' . esc_attr( $ls ) . ';';
			}
		}
		if ( ! empty( $styles['wordSpacing'] ) ) {
			$ws = sanitize_text_field( $styles['wordSpacing'] );
			if ( $ws ) {
				$piece[] = 'word-spacing:' . esc_attr( $ws ) . ';';
			}
		}
		if ( ! empty( $settings['st_stroke_width'] ) ) {
			$sw = max( 0, min( 20, (int) $settings['st_stroke_width'] ) );
			$sc = Jalpi_Sanitizer::sanitize_color( $settings['st_stroke_color'] ?? '' );
			if ( $sw && $sc ) {
				$piece[] = "-webkit-text-stroke:{$sw}px {$sc};";
			}
		}
		if ( ! empty( $settings['st_text_shadow'] ) ) {
			// Assembled from validated numbers + colour; never passed through raw.
			$sh = $settings['st_text_shadow'];
			$x  = (int) ( $sh['x'] ?? 0 );
			$y  = (int) ( $sh['y'] ?? 0 );
			$b  = max( 0, (int) ( $sh['blur'] ?? 0 ) );
			$c  = Jalpi_Sanitizer::sanitize_color( $sh['color'] ?? '' );
			if ( $c ) {
				$piece[] = "text-shadow:{$x}px {$y}px {$b}px {$c};";
			}
		}

		if ( $piece ) {
			$css .= "{$sel} .jalpi-st__p{" . implode( '', $piece ) . '}';
		}

		// Animated-state typography — only while the piece is mid-animation.
		if ( ! empty( $settings['st_anim_color'] ) ) {
			$ac = Jalpi_Sanitizer::sanitize_color( $settings['st_anim_color'] );
			if ( $ac ) {
				$css .= "{$sel}[data-jalpi-st-active] .jalpi-st__p{color:{$ac};}";
			}
		}

		$renderer->add_css( $css );

		// Tablet/mobile overrides need no work here: render_node() already runs
		// maybe_add_responsive_rules() for every node, and the default selector
		// it builds (.jalpi-el.jalpi-{id}) is exactly $sel.

		$st_attr = $this->split_text_attr( $settings );
		if ( $st_attr ) {
			$renderer->set_needs_js( 'generic' );
		}

		return "<{$tag} class=\"jalpi-el jalpi-{$id}{$a['extra_cls']}\"{$a['id_attr']}{$st_attr}>{$text}</{$tag}>";
	}
}
