<?php
/**
 * Builds Elementor JSON fragments from Niwa template manifests.
 *
 * @package Niwa_AI
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Niwa_AI_Template_Elementor_Builder {
	public function build_elements( $template, $instructions = '', $llm_elementor = array() ) {
		if ( is_array( $llm_elementor ) && ! empty( $llm_elementor ) && $this->is_element_list( $llm_elementor ) ) {
			return $this->normalize_elements( $llm_elementor );
		}

		$schema = isset( $template['elementor_schema'] ) && is_array( $template['elementor_schema'] ) ? $template['elementor_schema'] : array();
		$kind   = isset( $schema['kind'] ) ? sanitize_key( (string) $schema['kind'] ) : '';
		if ( '' === $kind ) {
			$kind = $this->infer_kind( $template );
		}

		switch ( $kind ) {
			case 'image_reveal_menu':
				return $this->image_reveal_menu( $template, $instructions, $schema );
			case 'team_accordion':
				return $this->team_accordion( $template, $instructions, $schema );
			case 'testimonial_carousel':
				return $this->testimonial_carousel( $template, $instructions, $schema );
			case 'pricing_cards':
				return $this->pricing_cards( $template, $instructions, $schema );
			case 'publishing_activity_widget':
				return $this->publishing_activity_widget( $template, $instructions, $schema );
			case 'custom_post_type_preview':
				return $this->custom_post_type_preview( $template, $instructions, $schema );
			case 'admin_dashboard_preview':
				return $this->admin_dashboard_preview( $template, $instructions, $schema );
			case 'admin_column_preview':
				return $this->admin_column_preview( $template, $instructions, $schema );
			case 'announcement_bar':
				return $this->announcement_bar( $template, $instructions, $schema );
			case 'faq_accordion':
				return $this->faq_accordion( $template, $instructions, $schema );
			case 'product_finder_quiz':
				return $this->product_finder_quiz( $template, $instructions, $schema );
			case 'quote_calculator':
				return $this->quote_calculator( $template, $instructions, $schema );
			case 'visual_app':
				return $this->visual_app( $template, $instructions, $schema );
			default:
				return $this->content_section( $template, $instructions, $schema );
		}
	}

	public function append_to_page_data( $current_data, $elements, $position = 'after' ) {
		$current_data = is_array( $current_data ) ? array_values( $current_data ) : array();
		$elements     = $this->normalize_elements( $elements );
		if ( empty( $elements ) ) {
			return $current_data;
		}
		if ( 'before' === sanitize_key( (string) $position ) ) {
			return array_merge( $elements, $current_data );
		}
		return array_merge( $current_data, $elements );
	}

	public function registered_widget_elements( $widget_name, $settings = array() ) {
		$widget_name = sanitize_key( (string) $widget_name );
		if ( '' === $widget_name ) {
			return array();
		}
		return array(
			$this->container(
				array(
					'content_width' => 'full',
					'padding'       => $this->dimensions( 0, 0, 0, 0 ),
				),
				array(
					$this->widget( $widget_name, is_array( $settings ) ? $settings : array() ),
				)
			),
		);
	}

	public function render_post_content( $elements ) {
		$parts = array();
		$this->collect_text( $elements, $parts );
		$text = trim( implode( "\n\n", array_filter( $parts ) ) );
		return '' !== $text ? wp_kses_post( wpautop( $text ) ) : '';
	}

	private function content_section( $template, $instructions, $schema ) {
		$title = isset( $schema['title'] ) && '' !== $schema['title'] ? (string) $schema['title'] : ( isset( $template['title'] ) ? (string) $template['title'] : 'Niwa section' );
		$body  = '' !== trim( (string) $instructions ) ? (string) $instructions : ( isset( $template['prompt'] ) ? (string) $template['prompt'] : '' );
		$cta   = isset( $schema['cta'] ) ? (string) $schema['cta'] : __( 'Learn more', 'niwa-ai' );

		return array(
			$this->container(
				array(
					'content_width' => 'boxed',
					'boxed_width'   => array( 'unit' => 'px', 'size' => 1180 ),
					'padding'       => $this->dimensions( 72, 24, 72, 24 ),
				),
				array(
					$this->widget( 'heading', array( 'title' => $title, 'header_size' => 'h2', 'align' => 'center' ) ),
					$this->widget( 'text-editor', array( 'editor' => wp_kses_post( wpautop( $body ) ), 'align' => 'center' ) ),
					$this->widget( 'button', array( 'text' => $cta, 'align' => 'center', 'button_type' => 'info' ) ),
				)
			),
		);
	}

	private function team_accordion( $template, $instructions, $schema ) {
		$people = isset( $schema['items'] ) && is_array( $schema['items'] ) ? $schema['items'] : array();
		if ( empty( $people ) ) {
			$people = array(
				array( 'name' => 'Ana', 'role' => 'Creative lead' ),
				array( 'name' => 'Miloš', 'role' => 'Strategy' ),
				array( 'name' => 'Jelena', 'role' => 'Operations' ),
			);
		}

		$children = array(
			$this->widget( 'heading', array( 'title' => isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'], 'header_size' => 'h2', 'align' => 'center' ) ),
		);
		foreach ( array_slice( $people, 0, 6 ) as $person ) {
			$name = isset( $person['name'] ) ? (string) $person['name'] : 'Team member';
			$role = isset( $person['role'] ) ? (string) $person['role'] : '';
			$children[] = $this->container(
				array(
					'content_width' => 'full',
					'padding'       => $this->dimensions( 18, 18, 18, 18 ),
				),
				array(
					$this->widget( 'heading', array( 'title' => $name, 'header_size' => 'h3' ) ),
					$this->widget( 'text-editor', array( 'editor' => esc_html( $role ) ) ),
				)
			);
		}

		return array( $this->container( array( 'content_width' => 'boxed', 'boxed_width' => array( 'unit' => 'px', 'size' => 1180 ), 'padding' => $this->dimensions( 64, 24, 64, 24 ) ), $children ) );
	}

	private function image_reveal_menu( $template, $instructions, $schema ) {
		$title  = isset( $schema['title'] ) && '' !== trim( (string) $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'];
		$eyebrow = isset( $schema['eyebrow'] ) && '' !== trim( (string) $schema['eyebrow'] ) ? (string) $schema['eyebrow'] : __( 'Explore', 'niwa-ai' );
		$intro  = isset( $schema['intro'] ) && '' !== trim( (string) $schema['intro'] ) ? (string) $schema['intro'] : __( 'Hover or focus each menu item to reveal the matching visual story.', 'niwa-ai' );
		$cta_text = isset( $schema['cta_text'] ) && '' !== trim( (string) $schema['cta_text'] ) ? (string) $schema['cta_text'] : __( 'Explore services', 'niwa-ai' );
		$cta_url  = isset( $schema['cta_url'] ) && '' !== trim( (string) $schema['cta_url'] ) ? (string) $schema['cta_url'] : '#';
		$accent   = isset( $schema['accent'] ) && '' !== trim( (string) $schema['accent'] ) ? (string) $schema['accent'] : '#7dd3fc';
		$items    = isset( $schema['items'] ) && is_array( $schema['items'] ) ? $schema['items'] : array();
		if ( empty( $items ) ) {
			$items = array(
				array(
					'label'       => 'Technical SEO',
					'description' => 'Architecture, speed, crawl paths, and search visibility cleanup.',
					'image_url'   => 'https://images.unsplash.com/photo-1451187580459-43490279c0fa?auto=format&fit=crop&w=1200&q=80',
				),
				array(
					'label'       => 'Content Strategy',
					'description' => 'Search-led topics, conversion intent, and publishing systems.',
					'image_url'   => 'https://images.unsplash.com/photo-1497366754035-f200968a6e72?auto=format&fit=crop&w=1200&q=80',
				),
				array(
					'label'       => 'On-page SEO',
					'description' => 'Sharper structure, copy, links, and page-level conversion signals.',
					'image_url'   => 'https://images.unsplash.com/photo-1516321318423-f06f85e504b3?auto=format&fit=crop&w=1200&q=80',
				),
				array(
					'label'       => 'SEO Audits',
					'description' => 'Prioritized fixes with impact, effort, and owner clarity.',
					'image_url'   => 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?auto=format&fit=crop&w=1200&q=80',
				),
			);
		}

		$menu_children = array();
		$image_children = array();
		foreach ( array_values( array_slice( $items, 0, 6 ) ) as $index => $item ) {
			$label = isset( $item['label'] ) ? (string) $item['label'] : 'Menu item';
			$desc  = isset( $item['description'] ) ? (string) $item['description'] : '';
			$image = isset( $item['image_url'] ) ? (string) $item['image_url'] : '';
			$menu_children[] = $this->container(
				array(
					'content_width' => 'full',
					'padding'       => $this->dimensions( 18, 18, 18, 18 ),
					'border_border' => 'solid',
					'border_width'  => $this->dimensions( 0, 0, 1, 0 ),
					'border_color'  => 'rgba(255,255,255,.18)',
				),
				array(
					$this->widget( 'heading', array( 'title' => str_pad( (string) ( $index + 1 ), 2, '0', STR_PAD_LEFT ), 'header_size' => 'h6', 'title_color' => $accent ) ),
					$this->widget( 'heading', array( 'title' => $label, 'header_size' => 'h3', 'title_color' => '#f8fafc' ) ),
					$this->widget( 'text-editor', array( 'editor' => esc_html( $desc ), 'text_color' => 'rgba(248,250,252,.72)' ) ),
				)
			);
			$image_children[] = $this->container(
				array(
					'content_width' => 'full',
					'padding'       => $this->dimensions( 14, 14, 14, 14 ),
					'width'         => array( 'unit' => '%', 'size' => 50 ),
				),
				array_filter(
					array(
						'' !== $image ? $this->widget( 'image', array( 'image' => array( 'url' => $image ), 'image_size' => 'large' ) ) : null,
						$this->widget( 'heading', array( 'title' => $label, 'header_size' => 'h4', 'title_color' => '#f8fafc' ) ),
					)
				)
			);
		}

		return array(
			$this->container(
				array(
					'content_width'      => 'full',
					'background_background' => 'classic',
					'background_color'   => '#020c0a',
					'padding'            => $this->dimensions( 88, 24, 88, 24 ),
				),
				array(
					$this->container(
						array(
							'content_width' => 'boxed',
							'boxed_width'   => array( 'unit' => 'px', 'size' => 1180 ),
							'padding'       => $this->dimensions( 0, 0, 36, 0 ),
						),
						array(
							$this->widget( 'heading', array( 'title' => $eyebrow, 'header_size' => 'h6', 'align' => 'left', 'title_color' => $accent ) ),
							$this->widget( 'heading', array( 'title' => $title, 'header_size' => 'h2', 'align' => 'left', 'title_color' => '#ffffff' ) ),
							$this->widget( 'text-editor', array( 'editor' => esc_html( $intro ), 'align' => 'left', 'text_color' => 'rgba(248,250,252,.72)' ) ),
							$this->widget( 'button', array( 'text' => $cta_text, 'link' => array( 'url' => $cta_url ), 'align' => 'left', 'button_background_color' => $accent, 'button_text_color' => '#07100d' ) ),
						)
					),
					$this->container(
						array(
							'content_width' => 'boxed',
							'boxed_width'   => array( 'unit' => 'px', 'size' => 1180 ),
						),
						array(
							$this->container( array( 'content_width' => 'full', 'width' => array( 'unit' => '%', 'size' => 42 ) ), $menu_children ),
							$this->container( array( 'content_width' => 'full', 'width' => array( 'unit' => '%', 'size' => 58 ) ), $image_children ),
						)
					),
				)
			),
		);
	}

	private function publishing_activity_widget( $template, $instructions, $schema ) {
		$title = isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'];
		$days  = array( 0, 1, 2, 0, 3, 4, 1, 2, 5, 0, 0, 3, 2, 6, 1, 4, 0, 3, 5, 2, 1, 0, 4, 6, 7, 2, 3, 1, 0, 5 );
		$total = array_sum( $days );
		$cells = array();
		foreach ( $days as $index => $value ) {
			$level = min( 4, intval( $value ) );
			$cells[] = $this->container(
				array(
					'content_width' => 'full',
					'padding'       => $this->dimensions( 7, 7, 7, 7 ),
					'background_background' => 'classic',
					'background_color' => $this->activity_color( $level ),
					'border_radius' => $this->dimensions( 4, 4, 4, 4 ),
					'width'         => array( 'unit' => '%', 'size' => 10 ),
				),
				array(
					$this->widget( 'heading', array( 'title' => (string) $value, 'header_size' => 'h6', 'align' => 'center', 'title_color' => $level >= 3 ? '#ffffff' : '#111827' ) ),
				)
			);
		}

		return array(
			$this->container(
				array(
					'content_width' => 'boxed',
					'boxed_width'   => array( 'unit' => 'px', 'size' => 1040 ),
					'padding'       => $this->dimensions( 72, 24, 72, 24 ),
				),
				array(
					$this->widget( 'heading', array( 'title' => 'WP Admin Preview', 'header_size' => 'h6', 'align' => 'center', 'title_color' => '#8a6116' ) ),
					$this->widget( 'heading', array( 'title' => $title, 'header_size' => 'h2', 'align' => 'center' ) ),
					$this->widget( 'text-editor', array( 'editor' => esc_html( $total . ' publishing events across the last 30 days.' ), 'align' => 'center' ) ),
					$this->container(
						array(
							'content_width' => 'full',
							'padding'       => $this->dimensions( 28, 28, 28, 28 ),
							'background_background' => 'classic',
							'background_color' => '#ffffff',
							'border_border' => 'solid',
							'border_width'  => $this->dimensions( 1, 1, 1, 1 ),
							'border_color'  => '#e5e7eb',
						),
						array_merge(
							array(
								$this->widget( 'heading', array( 'title' => 'Last 30 days', 'header_size' => 'h3' ) ),
								$this->widget( 'text-editor', array( 'editor' => esc_html( max( $days ) . ' posts on peak day. Use the generated admin snippet for live WP dashboard filtering.' ) ) ),
							),
							$cells
						)
					),
				)
			),
		);
	}

	private function custom_post_type_preview( $template, $instructions, $schema ) {
		$title = isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'];
		$html  = '<section class="niwa-tpl niwa-cpt-preview" data-niwa-template-section="custom-post-type" data-niwa-cpt-preview>';
		$html .= '<div class="niwa-tpl__head"><span>WordPress admin snippet</span><h2>' . esc_html( $title ) . '</h2><p>Backend CPT preview with working admin-style actions: add a draft, select rows, and inspect the generated registration package.</p></div>';
		$html .= '<div class="niwa-cpt-preview__panel"><aside aria-label="Generated admin menu"><b>Portfolio</b><button type="button" class="is-active" data-niwa-cpt-nav="all">All items</button><button type="button" data-niwa-cpt-add>Add new</button><button type="button" data-niwa-cpt-nav="settings">Settings</button></aside><main><div class="niwa-cpt-preview__toolbar"><div><strong>Portfolio items</strong><span data-niwa-cpt-status>3 registered admin rows</span></div><button type="button" data-niwa-cpt-add>Add new</button></div><div class="niwa-cpt-preview__table" role="table" aria-label="Portfolio admin rows" data-niwa-cpt-table><div class="niwa-cpt-preview__row head" role="row"><b>Title</b><b>Status</b><b>Type</b><b>Action</b></div><button type="button" class="niwa-cpt-preview__row" data-title="Case study"><b>Case study</b><span>Published</span><span>Featured</span><em>Edit</em></button><button type="button" class="niwa-cpt-preview__row" data-title="Landing page"><b>Landing page</b><span>Draft</span><span>Service</span><em>Edit</em></button><button type="button" class="niwa-cpt-preview__row" data-title="Campaign"><b>Campaign</b><span>Published</span><span>Growth</span><em>Edit</em></button></div><div class="niwa-cpt-preview__drawer" data-niwa-cpt-drawer hidden><div><small>Draft editor preview</small><strong data-niwa-cpt-drawer-title>New portfolio item</strong><p>Niwa would register this CPT in wp-admin, not as a dead public menu. This preview shows the generated backend behavior before install.</p></div><button type="button" data-niwa-cpt-save>Save draft</button></div></main></div>';
		$html .= '</section>' . $this->template_showcase_css() . '<style>.niwa-cpt-preview__panel{display:grid;grid-template-columns:200px 1fr;max-width:1040px;margin:0 auto;border:1px solid rgba(15,23,42,.1);border-radius:8px;background:#fff;overflow:hidden;box-shadow:0 24px 60px rgba(15,23,42,.08)}.niwa-cpt-preview aside{display:flex;flex-direction:column;gap:10px;padding:26px;background:#f6f2e9;color:#64748b}.niwa-cpt-preview aside b{margin-bottom:8px;color:#111827}.niwa-cpt-preview aside button,.niwa-cpt-preview__toolbar button,.niwa-cpt-preview__drawer button{border:1px solid transparent!important;border-radius:6px!important;background:transparent;color:#334155;padding:10px 12px!important;text-align:left;font-weight:700;cursor:pointer}.niwa-cpt-preview aside button.is-active,.niwa-cpt-preview aside button:hover,.niwa-cpt-preview aside button:focus-visible{background:#07100d!important;color:#fff!important;outline:none!important}.niwa-cpt-preview main{padding:26px}.niwa-cpt-preview__toolbar{display:flex;justify-content:space-between;gap:12px;align-items:center;margin-bottom:18px}.niwa-cpt-preview__toolbar strong{display:block;color:#111827}.niwa-cpt-preview__toolbar span{display:block;margin-top:4px;color:#64748b;font-size:13px}.niwa-cpt-preview__toolbar button,.niwa-cpt-preview__drawer button{background:#07100d!important;color:#fff!important;text-align:center}.niwa-cpt-preview__toolbar button:hover,.niwa-cpt-preview__toolbar button:focus-visible,.niwa-cpt-preview__drawer button:hover,.niwa-cpt-preview__drawer button:focus-visible{background:#d6b46a!important;color:#07100d!important;outline:none!important}.niwa-cpt-preview__table{border:1px solid #e5e7eb;border-radius:8px;overflow:hidden}.niwa-cpt-preview__row{display:grid;grid-template-columns:1fr 120px 120px 72px;gap:12px;width:100%;padding:14px 16px;border:0;border-top:1px solid #e5e7eb;background:#fff;color:#475569;text-align:left;cursor:pointer}.niwa-cpt-preview__row:first-child{border-top:0}.niwa-cpt-preview__row.head{border-top:0;background:#f8fafc;color:#334155;cursor:default}.niwa-cpt-preview__row:not(.head):hover,.niwa-cpt-preview__row:not(.head).is-active{background:#fff8e8;outline:2px solid rgba(214,180,106,.36);outline-offset:-2px}.niwa-cpt-preview__row b{color:#111827}.niwa-cpt-preview__row em{font-style:normal;color:#8a6116;font-weight:700}.niwa-cpt-preview__drawer{display:flex;justify-content:space-between;gap:18px;align-items:center;margin-top:18px;padding:18px;border:1px solid rgba(214,180,106,.45);border-radius:8px;background:#fff8e8}.niwa-cpt-preview__drawer[hidden]{display:none}.niwa-cpt-preview__drawer small{display:block;color:#8a6116;font-weight:800;text-transform:uppercase}.niwa-cpt-preview__drawer strong{display:block;margin:6px 0;color:#111827;font-size:22px}.niwa-cpt-preview__drawer p{margin:0;color:#64748b}@media(max-width:720px){.niwa-cpt-preview__panel{grid-template-columns:1fr}.niwa-cpt-preview__row{grid-template-columns:1fr}.niwa-cpt-preview__row.head{display:none}.niwa-cpt-preview__drawer{display:block}.niwa-cpt-preview__drawer button{margin-top:14px}}</style>';
		$html .= '<script>(function(){document.querySelectorAll("[data-niwa-cpt-preview]").forEach(function(root){var table=root.querySelector("[data-niwa-cpt-table]");var drawer=root.querySelector("[data-niwa-cpt-drawer]");var drawerTitle=root.querySelector("[data-niwa-cpt-drawer-title]");var status=root.querySelector("[data-niwa-cpt-status]");var addButtons=root.querySelectorAll("[data-niwa-cpt-add]");var save=root.querySelector("[data-niwa-cpt-save]");function rows(){return root.querySelectorAll(".niwa-cpt-preview__row:not(.head)");}function selectRow(row){rows().forEach(function(item){item.classList.remove("is-active")});row.classList.add("is-active");drawer.hidden=false;drawerTitle.textContent="Editing "+row.getAttribute("data-title");status.textContent=row.getAttribute("data-title")+" selected";}rows().forEach(function(row){row.addEventListener("click",function(){selectRow(row);});});addButtons.forEach(function(btn){btn.addEventListener("click",function(){var draft=document.createElement("button");draft.type="button";draft.className="niwa-cpt-preview__row";draft.setAttribute("data-title","New portfolio item");draft.innerHTML="<b>New portfolio item</b><span>Draft</span><span>Generated</span><em>Edit</em>";table.insertBefore(draft,table.children[1]);draft.addEventListener("click",function(){selectRow(draft);});selectRow(draft);status.textContent="Draft row added in backend preview";});});save.addEventListener("click",function(){status.textContent="Draft saved in preview";});});})();</script>';
		return $this->html_section( $html );
	}

	private function admin_dashboard_preview( $template, $instructions, $schema ) {
		$title = isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'];
		$html  = '<section class="niwa-tpl niwa-admin-dashboard-preview" data-niwa-template-section="admin-dashboard-widget" data-niwa-dashboard-preview>';
		$html .= '<div class="niwa-tpl__head"><span>WordPress admin snippet</span><h2>' . esc_html( $title ) . '</h2><p>Operational dashboard card with clickable metrics, capability-safe admin actions, and a readable detail panel.</p></div>';
		$html .= '<div class="niwa-admin-dashboard-preview__wrap"><div class="niwa-admin-dashboard-preview__grid"><button type="button" class="is-active" data-detail="18 leads are awaiting reply. Niwa would open the filtered Leads admin screen."><span>Open leads</span><strong>42</strong><em>+12% this week</em></button><button type="button" data-detail="18 orders need review. Niwa would open WooCommerce orders with the same filter."><span>Orders</span><strong>128</strong><em>18 awaiting action</em></button><button type="button" data-detail="Three pages need metadata or content review before publishing."><span>Content health</span><strong>91%</strong><em>3 pages need review</em></button></div><output data-niwa-dashboard-output>18 leads are awaiting reply. Niwa would open the filtered Leads admin screen.</output></div>';
		$html .= '</section>' . $this->template_showcase_css() . '<style>.niwa-admin-dashboard-preview__wrap{max-width:1040px;margin:0 auto}.niwa-admin-dashboard-preview__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}.niwa-admin-dashboard-preview button{padding:28px;border:1px solid rgba(15,23,42,.1);border-radius:8px;background:#fff;box-shadow:0 24px 60px rgba(15,23,42,.08);text-align:left;cursor:pointer;transition:transform .18s ease,border-color .18s ease}.niwa-admin-dashboard-preview button:hover,.niwa-admin-dashboard-preview button:focus-visible,.niwa-admin-dashboard-preview button.is-active{border-color:rgba(214,180,106,.75);transform:translateY(-3px);outline:none}.niwa-admin-dashboard-preview span{display:block;color:#64748b}.niwa-admin-dashboard-preview strong{display:block;margin:10px 0;color:#111827;font-size:46px;line-height:1}.niwa-admin-dashboard-preview em{color:#16a34a;font-style:normal}.niwa-admin-dashboard-preview output{display:block;margin-top:18px;padding:18px;border-left:4px solid var(--niwa-tpl-accent,#d6b46a);border-radius:8px;background:#fff;color:#334155;box-shadow:0 14px 40px rgba(15,23,42,.06)}@media(max-width:760px){.niwa-admin-dashboard-preview__grid{grid-template-columns:1fr}}</style>';
		$html .= '<script>(function(){document.querySelectorAll("[data-niwa-dashboard-preview]").forEach(function(root){var buttons=root.querySelectorAll("[data-detail]");var output=root.querySelector("[data-niwa-dashboard-output]");buttons.forEach(function(btn){btn.addEventListener("click",function(){buttons.forEach(function(item){item.classList.remove("is-active")});btn.classList.add("is-active");output.textContent=btn.getAttribute("data-detail");});});});})();</script>';
		return $this->html_section( $html );
	}

	private function admin_column_preview( $template, $instructions, $schema ) {
		$title = isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'];
		$html  = '<section class="niwa-tpl niwa-admin-columns-preview" data-niwa-template-section="admin-column-enhancer" data-niwa-admin-columns>';
		$html .= '<div class="niwa-tpl__head"><span>WordPress admin snippet</span><h2>' . esc_html( $title ) . '</h2><p>Sortable admin columns for key metadata, status scanning, and faster content operations.</p></div>';
		$html .= '<div class="niwa-admin-columns-preview__table"><div class="head"><button type="button" data-sort="title">Title</button><button type="button" data-sort="priority">Priority</button><button type="button" data-sort="owner">Owner</button><button type="button" data-sort="updated">Updated</button></div><div data-niwa-admin-rows><div class="niwa-admin-columns-preview__row" data-title="Homepage" data-priority="3" data-owner="Marketing" data-updated="3"><span>Homepage</span><mark>High</mark><span>Marketing</span><span>Today</span></div><div class="niwa-admin-columns-preview__row" data-title="Service page" data-priority="2" data-owner="Sales" data-updated="2"><span>Service page</span><mark>Medium</mark><span>Sales</span><span>Yesterday</span></div><div class="niwa-admin-columns-preview__row" data-title="FAQ" data-priority="1" data-owner="Support" data-updated="1"><span>FAQ</span><mark>Low</mark><span>Support</span><span>Jun 18</span></div></div></div><output data-niwa-admin-columns-output>Sorted by current admin order.</output>';
		$html .= '</section>' . $this->template_showcase_css() . '<style>.niwa-admin-columns-preview__table{max-width:980px;margin:0 auto;border:1px solid rgba(15,23,42,.1);border-radius:8px;background:#fff;overflow:hidden;box-shadow:0 24px 60px rgba(15,23,42,.08)}.niwa-admin-columns-preview__table .head,.niwa-admin-columns-preview__row{display:grid;grid-template-columns:1.4fr .7fr .9fr .8fr;gap:12px;padding:16px 20px;border-top:1px solid #e5e7eb}.niwa-admin-columns-preview__table .head{border-top:0;background:#f8fafc;color:#334155}.niwa-admin-columns-preview__table .head button{border:0;background:transparent;color:inherit;text-align:left;font-weight:800;cursor:pointer}.niwa-admin-columns-preview__table .head button.is-active{color:#8a6116}.niwa-admin-columns-preview mark{justify-self:start;border-radius:999px;background:#fff0c8;color:#805a12;padding:3px 9px}.niwa-admin-columns-preview output{display:block;max-width:980px;margin:14px auto 0;color:#64748b}@media(max-width:720px){.niwa-admin-columns-preview__table .head{display:none}.niwa-admin-columns-preview__row{grid-template-columns:1fr}}</style>';
		$html .= '<script>(function(){document.querySelectorAll("[data-niwa-admin-columns]").forEach(function(root){var body=root.querySelector("[data-niwa-admin-rows]");var output=root.querySelector("[data-niwa-admin-columns-output]");root.querySelectorAll("[data-sort]").forEach(function(btn){btn.addEventListener("click",function(){var key=btn.getAttribute("data-sort");var rows=Array.prototype.slice.call(body.children);root.querySelectorAll("[data-sort]").forEach(function(item){item.classList.remove("is-active")});btn.classList.add("is-active");rows.sort(function(a,b){var av=a.getAttribute("data-"+key);var bv=b.getAttribute("data-"+key);if(key==="priority"||key==="updated"){return parseInt(bv,10)-parseInt(av,10);}return av.localeCompare(bv);});rows.forEach(function(row){body.appendChild(row);});output.textContent="Sorted by "+btn.textContent.trim()+" column.";});});});})();</script>';
		return $this->html_section( $html );
	}

	private function announcement_bar( $template, $instructions, $schema ) {
		$message = isset( $schema['message'] ) ? (string) $schema['message'] : __( 'A new update is live.', 'niwa-ai' );
		$cta     = isset( $schema['cta_text'] ) ? (string) $schema['cta_text'] : __( 'Learn more', 'niwa-ai' );
		$url     = isset( $schema['cta_url'] ) ? (string) $schema['cta_url'] : '#';
		$design  = $this->site_design_config();
		$bg      = isset( $design['background_color'] ) ? (string) $design['background_color'] : '#07100d';
		$panel   = isset( $design['card_background'] ) ? (string) $design['card_background'] : '#f8f3e6';
		$muted   = isset( $design['muted_color'] ) ? (string) $design['muted_color'] : '#64748b';
		$accent  = isset( $design['accent_color'] ) ? (string) $design['accent_color'] : '#8a6116';
		$button  = isset( $design['button_background'] ) ? (string) $design['button_background'] : '#07100d';
		$button_text = isset( $design['button_text_color'] ) ? (string) $design['button_text_color'] : '#ffffff';
		return array(
			$this->container(
				array(
					'content_width' => 'full',
					'padding'       => $this->dimensions( 36, 24, 36, 24 ),
					'background_background' => 'classic',
					'background_color' => $bg,
				),
				array(
					$this->container(
						array(
							'content_width' => 'boxed',
							'boxed_width'   => array( 'unit' => 'px', 'size' => 1180 ),
							'padding'       => $this->dimensions( 20, 22, 20, 22 ),
							'background_background' => 'classic',
							'background_color' => $panel,
							'border_border' => 'solid',
							'border_width'  => $this->dimensions( 1, 1, 1, 1 ),
							'border_color'  => $accent,
							'border_radius' => $this->dimensions( 8, 8, 8, 8 ),
						),
						array(
							$this->widget( 'heading', array( 'title' => __( 'Seasonal update', 'niwa-ai' ), 'header_size' => 'h6', 'align' => 'center', 'title_color' => $accent ) ),
							$this->widget( 'text-editor', array( 'editor' => esc_html( $message ), 'align' => 'center', 'text_color' => $muted ) ),
							$this->widget( 'button', array( 'text' => $cta, 'link' => array( 'url' => $url ), 'align' => 'center', 'button_background_color' => $button, 'button_text_color' => $button_text, 'text_color' => $button_text, 'background_color' => $button ) ),
						)
					),
				)
			),
		);
	}

	private function product_finder_quiz( $template, $instructions, $schema ) {
		$title = isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'];
		$html  = '<section class="niwa-quiz-app" data-niwa-template-section="product-finder-quiz" data-niwa-product-quiz><div class="niwa-quiz-app__inner"><div><span>Visual app</span><h2>' . esc_html( $title ) . '</h2><p>Guide visitors to the right offer with choices, scoring, and a recommendation that changes immediately.</p></div><form><label class="is-active"><input type="radio" name="niwa_quiz_goal" value="gift" checked> Gift experience</label><label><input type="radio" name="niwa_quiz_goal" value="pantry"> Everyday pantry</label><label><input type="radio" name="niwa_quiz_goal" value="chef"> Chef-grade ingredient</label><button type="button" data-niwa-quiz-submit>Show recommendation</button></form><aside><small>Best match</small><strong data-niwa-quiz-title>Curated discovery set</strong><p data-niwa-quiz-copy>Balanced entry point with premium presentation and a simple CTA.</p><a href="#shop" data-niwa-quiz-cta>Explore gift set</a></aside></div></section>';
		$html .= '<style>.niwa-quiz-app{padding:clamp(56px,8vw,96px) clamp(18px,5vw,72px);background:#f8fafc}.niwa-quiz-app__inner{display:grid;grid-template-columns:1fr .9fr .9fr;gap:22px;max-width:1180px;margin:0 auto;align-items:stretch}.niwa-quiz-app span,.niwa-quiz-app small{color:#8a6116;font-weight:700;text-transform:uppercase;font-size:12px}.niwa-quiz-app h2{margin:10px 0 12px;color:#111827;font-size:clamp(32px,4vw,56px);line-height:1}.niwa-quiz-app p{color:#64748b;line-height:1.65}.niwa-quiz-app form,.niwa-quiz-app aside{padding:26px;border:1px solid #e5e7eb;border-radius:8px;background:#fff}.niwa-quiz-app label{display:block;margin-bottom:12px;padding:12px;border:1px solid #e5e7eb;border-radius:6px;color:#111827;cursor:pointer}.niwa-quiz-app label.is-active{border-color:#d6b46a;background:#fff8e8}.niwa-quiz-app input{margin-right:8px}.niwa-quiz-app button,.niwa-quiz-app a{display:inline-flex;align-items:center;justify-content:center;margin-top:8px;border:0;border-radius:6px;background:#111827;color:#fff;padding:12px 16px;text-decoration:none;font-weight:700;cursor:pointer}.niwa-quiz-app aside strong{display:block;margin:10px 0;color:#111827;font-size:28px;line-height:1.1}@media(max-width:880px){.niwa-quiz-app__inner{grid-template-columns:1fr}}</style>';
		$html .= '<script>(function(){document.querySelectorAll("[data-niwa-product-quiz]").forEach(function(root){var data={gift:["Curated discovery set","Balanced entry point with premium presentation and a simple CTA.","Explore gift set"],pantry:["Everyday pantry trio","Use this when the visitor wants easy repeat use, pantry restock, and clear value.","Build pantry box"],chef:["Chef-grade ingredient kit","Best for experienced cooks who need stronger product detail, usage notes, and pairing guidance.","See chef kit"]};var radios=root.querySelectorAll("input[name=niwa_quiz_goal]");var title=root.querySelector("[data-niwa-quiz-title]");var copy=root.querySelector("[data-niwa-quiz-copy]");var cta=root.querySelector("[data-niwa-quiz-cta]");function apply(value){root.querySelectorAll("label").forEach(function(label){label.classList.toggle("is-active",label.querySelector("input").value===value);});title.textContent=data[value][0];copy.textContent=data[value][1];cta.textContent=data[value][2];}radios.forEach(function(radio){radio.addEventListener("change",function(){apply(radio.value);});});root.querySelector("[data-niwa-quiz-submit]").addEventListener("click",function(){var checked=root.querySelector("input[name=niwa_quiz_goal]:checked");apply(checked?checked.value:"gift");});});})();</script>';
		return $this->html_section( $html );
	}

	private function quote_calculator( $template, $instructions, $schema ) {
		$title = isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'];
		$html  = '<section class="niwa-quote-calculator" data-niwa-template-section="quote-calculator"><div class="niwa-quote-calculator__inner"><div class="niwa-quote-calculator__copy"><span>Visual app</span><h2>' . esc_html( $title ) . '</h2><p>Interactive estimate surface with live total, validation-ready inputs, and lead handoff CTA.</p></div><div class="niwa-quote-calculator__card" data-niwa-quote-calc><label>Quantity<input type="range" min="1" max="12" value="4" data-qty></label><label>Package<select data-tier><option value="80">Standard</option><option value="140">Premium</option><option value="220">Concierge</option></select></label><output>Estimated total: <strong data-total>$320</strong></output><button type="button">Request quote</button></div></div></section>';
		$html .= '<style>.niwa-quote-calculator{padding:clamp(56px,8vw,96px) clamp(18px,5vw,72px);background:#080f0c;color:#fff}.niwa-quote-calculator__inner{display:grid;grid-template-columns:1fr 460px;gap:44px;max-width:1180px;margin:0 auto;align-items:center}.niwa-quote-calculator span{color:#d6b46a;font-weight:700;text-transform:uppercase;font-size:12px}.niwa-quote-calculator h2{margin:10px 0 14px;color:#fff;font-size:clamp(34px,5vw,64px);line-height:1}.niwa-quote-calculator p{color:rgba(255,255,255,.68);line-height:1.7}.niwa-quote-calculator__card{padding:30px;border:1px solid rgba(214,180,106,.34);border-radius:8px;background:rgba(255,255,255,.06);box-shadow:0 30px 80px rgba(0,0,0,.28)}.niwa-quote-calculator label{display:block;margin-bottom:20px;color:rgba(255,255,255,.82)}.niwa-quote-calculator input,.niwa-quote-calculator select{width:100%;margin-top:8px}.niwa-quote-calculator select{height:44px;border-radius:6px;border:1px solid rgba(255,255,255,.22);background:#fff;color:#111827}.niwa-quote-calculator output{display:block;margin:18px 0;font-size:18px}.niwa-quote-calculator output strong{color:#d6b46a;font-size:34px}.niwa-quote-calculator button{border:0;border-radius:6px;background:#d6b46a;color:#111827;padding:12px 16px;font-weight:700}@media(max-width:860px){.niwa-quote-calculator__inner{grid-template-columns:1fr}}</style><script>(function(){document.querySelectorAll("[data-niwa-quote-calc]").forEach(function(root){var qty=root.querySelector("[data-qty]");var tier=root.querySelector("[data-tier]");var total=root.querySelector("[data-total]");function update(){total.textContent="$"+(parseInt(qty.value,10)*parseInt(tier.value,10));}qty.addEventListener("input",update);tier.addEventListener("change",update);update();});})();</script>';
		return $this->html_section( $html );
	}

	private function testimonial_carousel( $template, $instructions, $schema ) {
		$items = isset( $schema['items'] ) && is_array( $schema['items'] ) ? $schema['items'] : array(
			array( 'content' => 'Clear, fast and useful from the first session.', 'name' => 'Customer' ),
			array( 'content' => 'The page finally explains the offer properly.', 'name' => 'Founder' ),
		);
		$children = array(
			$this->widget( 'heading', array( 'title' => isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'], 'header_size' => 'h2', 'align' => 'center' ) ),
		);
		foreach ( array_slice( $items, 0, 4 ) as $item ) {
			$content = isset( $item['content'] ) ? (string) $item['content'] : '';
			$name    = isset( $item['name'] ) ? (string) $item['name'] : '';
			$children[] = $this->container(
				array( 'content_width' => 'full', 'padding' => $this->dimensions( 24, 24, 24, 24 ) ),
				array(
					$this->widget( 'text-editor', array( 'editor' => esc_html( $content ) ) ),
					$this->widget( 'heading', array( 'title' => $name, 'header_size' => 'h4' ) ),
				)
			);
		}

		return array(
			$this->container(
				array( 'content_width' => 'boxed', 'boxed_width' => array( 'unit' => 'px', 'size' => 1100 ), 'padding' => $this->dimensions( 64, 24, 64, 24 ) ),
				$children
			),
		);
	}

	private function pricing_cards( $template, $instructions, $schema ) {
		$plans = isset( $schema['plans'] ) && is_array( $schema['plans'] ) ? $schema['plans'] : array(
			array( 'title' => 'Starter', 'price' => '€49', 'features' => 'Fast launch, Core sections, Basic support' ),
			array( 'title' => 'Growth', 'price' => '€149', 'features' => 'Custom layout, Automations, Priority support' ),
			array( 'title' => 'Scale', 'price' => 'Custom', 'features' => 'Advanced workflows, Integrations, Dedicated support' ),
		);
		$children = array( $this->widget( 'heading', array( 'title' => isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'], 'header_size' => 'h2', 'align' => 'center' ) ) );
		foreach ( array_slice( $plans, 0, 4 ) as $plan ) {
			$title = isset( $plan['title'] ) ? (string) $plan['title'] : 'Plan';
			$price = isset( $plan['price'] ) ? (string) $plan['price'] : '';
			$features = isset( $plan['features'] ) ? (string) $plan['features'] : '';
			$children[] = $this->container(
				array( 'content_width' => 'full', 'padding' => $this->dimensions( 24, 24, 24, 24 ) ),
				array(
					$this->widget( 'heading', array( 'title' => $title, 'header_size' => 'h3' ) ),
					$this->widget( 'heading', array( 'title' => $price, 'header_size' => 'h4' ) ),
					$this->widget( 'text-editor', array( 'editor' => esc_html( $features ) ) ),
					$this->widget( 'button', array( 'text' => __( 'Choose plan', 'niwa-ai' ) ) ),
				)
			);
		}
		return array( $this->container( array( 'content_width' => 'boxed', 'boxed_width' => array( 'unit' => 'px', 'size' => 1180 ), 'padding' => $this->dimensions( 64, 24, 64, 24 ) ), $children ) );
	}

	private function faq_accordion( $template, $instructions, $schema ) {
		$items = isset( $schema['items'] ) && is_array( $schema['items'] ) ? $schema['items'] : array(
			array( 'tab_title' => 'How does this work?', 'tab_content' => '' !== trim( (string) $instructions ) ? (string) $instructions : (string) $template['prompt'] ),
			array( 'tab_title' => 'Can it be customized?', 'tab_content' => 'Yes. Niwa adapts the content, styling and placement to the current page.' ),
		);
		return array(
			$this->container(
				array( 'content_width' => 'boxed', 'boxed_width' => array( 'unit' => 'px', 'size' => 980 ), 'padding' => $this->dimensions( 64, 24, 64, 24 ) ),
				array(
					$this->widget( 'heading', array( 'title' => isset( $schema['title'] ) ? (string) $schema['title'] : (string) $template['title'], 'header_size' => 'h2', 'align' => 'center' ) ),
					$this->widget( 'toggle', array( 'tabs' => $items ) ),
				)
			),
		);
	}

	private function visual_app( $template, $instructions, $schema ) {
		$title = isset( $schema['title'] ) && '' !== trim( (string) $schema['title'] ) ? (string) $schema['title'] : ( isset( $template['title'] ) ? (string) $template['title'] : 'Niwa visual app' );
		$body  = '' !== trim( (string) $instructions ) ? (string) $instructions : ( isset( $template['prompt'] ) ? (string) $template['prompt'] : '' );
		return array(
			$this->container(
				array( 'content_width' => 'boxed', 'boxed_width' => array( 'unit' => 'px', 'size' => 920 ), 'padding' => $this->dimensions( 64, 24, 64, 24 ) ),
				array(
					$this->widget( 'heading', array( 'title' => $title, 'header_size' => 'h2', 'align' => 'center' ) ),
					$this->widget( 'text-editor', array( 'editor' => wp_kses_post( wpautop( $body ) ), 'align' => 'center' ) ),
					$this->widget( 'button', array( 'text' => __( 'Use this app', 'niwa-ai' ), 'align' => 'center' ) ),
				)
			),
		);
	}

	private function html_section( $html ) {
		$text = trim( preg_replace( '/\s+/', ' ', wp_strip_all_tags( (string) $html ) ) );
		if ( '' === $text ) {
			$text = __( 'Niwa generated this template as an editable Elementor fallback.', 'niwa-ai' );
		}
		return array(
			$this->container(
				array(
					'content_width' => 'boxed',
					'boxed_width'   => array( 'unit' => 'px', 'size' => 920 ),
					'padding'       => $this->dimensions( 64, 24, 64, 24 ),
				),
				array(
					$this->widget( 'text-editor', array( 'editor' => esc_html( $text ), 'align' => 'center' ) ),
				)
			),
		);
	}

	private function site_design_config() {
		if ( ! class_exists( 'Niwa_AI_Template_Design_Context' ) ) {
			return array();
		}
		$config = ( new Niwa_AI_Template_Design_Context() )->apply_to_widget_config( array() );
		return is_array( $config ) ? $config : array();
	}

	private function activity_color( $level ) {
		$level = intval( $level );
		if ( $level >= 4 ) {
			return '#07100d';
		}
		if ( 3 === $level ) {
			return '#9d7a29';
		}
		if ( 2 === $level ) {
			return '#d6b46a';
		}
		if ( 1 === $level ) {
			return '#eadfca';
		}
		return '#f7f2e7';
	}

	private function template_showcase_css() {
		return '<style>.niwa-tpl{--niwa-tpl-primary:#07100d;--niwa-tpl-accent:#d6b46a;padding:clamp(56px,8vw,96px) clamp(18px,5vw,72px);background:#f8fafc;color:#111827}.niwa-tpl *{box-sizing:border-box}.niwa-tpl button{font:inherit;appearance:none!important;box-sizing:border-box;min-width:0!important;line-height:1.1!important}.niwa-tpl__head{max-width:820px;margin:0 auto 30px;text-align:center}.niwa-tpl__head span{display:inline-flex;margin-bottom:12px;color:#8a6116;font-size:12px;font-weight:700;text-transform:uppercase}.niwa-tpl__head h2{margin:0 0 12px;color:#111827;font-size:clamp(32px,4vw,56px);line-height:1;letter-spacing:0}.niwa-tpl__head p{margin:0;color:#64748b;font-size:16px;line-height:1.65}</style>';
	}

	private function container( $settings = array(), $children = array() ) {
		return array(
			'id'       => $this->element_id(),
			'elType'   => 'container',
			'settings' => is_array( $settings ) ? $settings : array(),
			'elements' => $this->normalize_elements( $children ),
		);
	}

	private function widget( $type, $settings = array() ) {
		return array(
			'id'         => $this->element_id(),
			'elType'     => 'widget',
			'widgetType' => sanitize_key( (string) $type ),
			'settings'   => is_array( $settings ) ? $settings : array(),
			'elements'   => array(),
		);
	}

	private function dimensions( $top, $right, $bottom, $left ) {
		return array(
			'unit'     => 'px',
			'top'      => (string) intval( $top ),
			'right'    => (string) intval( $right ),
			'bottom'   => (string) intval( $bottom ),
			'left'     => (string) intval( $left ),
			'isLinked' => false,
		);
	}

	private function normalize_elements( $elements ) {
		$normalized = array();
		foreach ( is_array( $elements ) ? $elements : array() as $element ) {
			if ( ! is_array( $element ) ) {
				continue;
			}
			if ( empty( $element['id'] ) ) {
				$element['id'] = $this->element_id();
			}
			if ( empty( $element['elType'] ) ) {
				$element['elType'] = isset( $element['widgetType'] ) ? 'widget' : 'container';
			}
			if ( ! isset( $element['settings'] ) || ! is_array( $element['settings'] ) ) {
				$element['settings'] = array();
			}
			if ( 'widget' === $element['elType'] && isset( $element['widgetType'] ) && 'html' === sanitize_key( (string) $element['widgetType'] ) ) {
				$html                  = isset( $element['settings']['html'] ) ? (string) $element['settings']['html'] : '';
				$element['widgetType'] = 'text-editor';
				$element['settings']   = array(
					'editor' => wp_kses_post( wpautop( trim( wp_strip_all_tags( $html ) ) ) ),
				);
			}
			if ( ! isset( $element['elements'] ) || ! is_array( $element['elements'] ) ) {
				$element['elements'] = array();
			}
			$element['elements'] = $this->normalize_elements( $element['elements'] );
			$normalized[] = $element;
		}
		return $normalized;
	}

	private function is_element_list( $value ) {
		if ( empty( $value ) || ! is_array( $value ) ) {
			return false;
		}
		foreach ( $value as $item ) {
			if ( ! is_array( $item ) || empty( $item['elType'] ) ) {
				return false;
			}
		}
		return true;
	}

	private function infer_kind( $template ) {
		$title = strtolower( isset( $template['title'] ) ? (string) $template['title'] : '' );
		if ( false !== strpos( $title, 'image reveal' ) || false !== strpos( $title, 'reveal menu' ) ) {
			return 'image_reveal_menu';
		}
		if ( false !== strpos( $title, 'team' ) || false !== strpos( $title, 'accordion' ) ) {
			return 'team_accordion';
		}
		if ( false !== strpos( $title, 'testimonial' ) ) {
			return 'testimonial_carousel';
		}
		if ( false !== strpos( $title, 'pricing' ) ) {
			return 'pricing_cards';
		}
		if ( false !== strpos( $title, 'publishing activity' ) ) {
			return 'publishing_activity_widget';
		}
		if ( false !== strpos( $title, 'custom post type' ) ) {
			return 'custom_post_type_preview';
		}
		if ( false !== strpos( $title, 'admin dashboard' ) ) {
			return 'admin_dashboard_preview';
		}
		if ( false !== strpos( $title, 'admin column' ) ) {
			return 'admin_column_preview';
		}
		if ( false !== strpos( $title, 'announcement' ) ) {
			return 'announcement_bar';
		}
		if ( false !== strpos( $title, 'faq' ) ) {
			return 'faq_accordion';
		}
		if ( false !== strpos( $title, 'product finder' ) || false !== strpos( $title, 'quiz' ) ) {
			return 'product_finder_quiz';
		}
		if ( false !== strpos( $title, 'quote calculator' ) || false !== strpos( $title, 'calculator' ) ) {
			return 'quote_calculator';
		}
		if ( isset( $template['type'] ) && Niwa_AI_Template_Library_Types::TYPE_VISUAL_APP === (string) $template['type'] ) {
			return 'visual_app';
		}
		return 'content_section';
	}

	private function collect_text( $elements, &$parts ) {
		foreach ( is_array( $elements ) ? $elements : array() as $element ) {
			if ( ! is_array( $element ) ) {
				continue;
			}
			$settings = isset( $element['settings'] ) && is_array( $element['settings'] ) ? $element['settings'] : array();
			foreach ( array( 'title', 'editor', 'text', 'html' ) as $key ) {
				if ( isset( $settings[ $key ] ) && is_string( $settings[ $key ] ) ) {
					$parts[] = wp_strip_all_tags( $settings[ $key ] );
				}
			}
			if ( isset( $element['elements'] ) ) {
				$this->collect_text( $element['elements'], $parts );
			}
		}
	}

	private function element_id() {
		try {
			return substr( bin2hex( random_bytes( 4 ) ), 0, 7 );
		} catch ( Exception $e ) {
			return substr( md5( uniqid( 'niwa', true ) ), 0, 7 );
		}
	}
}
