<?php
/**
 * Creates template/snippet artifacts from local prompts or optional LLM output.
 *
 * @package Niwa_AI
 */

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

class Niwa_AI_Template_AI_Generator {
	private $openai_client;
	private $auth_manager;
	private $model_router;
	private $elementor_builder;

	public function __construct( $openai_client = null, $auth_manager = null, $model_router = null, $elementor_builder = null ) {
		$this->openai_client    = $openai_client;
		$this->auth_manager     = $auth_manager;
		$this->model_router     = $model_router;
		$this->elementor_builder = $elementor_builder ? $elementor_builder : new Niwa_AI_Template_Elementor_Builder();
	}

	public function generate_files( $template, $instructions = '', $force_shortcode = false ) {
		$llm = $this->generate_with_llm( $template, $instructions, $force_shortcode );
		if ( ! empty( $llm['files'] ) && is_array( $llm['files'] ) ) {
			return $this->normalize_files( $llm['files'] );
		}

		$type = isset( $template['output_mode'] ) ? sanitize_key( (string) $template['output_mode'] ) : 'shortcode';
		if ( $force_shortcode || 'elementor_widget' === $type || 'visual_app' === $type || 'shortcode' === $type ) {
			return $this->frontend_files( $template, $instructions );
		}
		if ( 'admin_snippet' === $type ) {
			return $this->admin_files( $template, $instructions );
		}
		return $this->frontend_files( $template, $instructions );
	}

	public function generate_artifact( $template, $instructions = '', $force_shortcode = false ) {
		$llm = $this->generate_with_llm( $template, $instructions, $force_shortcode );
		$files = ! empty( $llm['files'] ) && is_array( $llm['files'] )
			? $this->normalize_files( $llm['files'] )
			: $this->fallback_files( $template, $instructions, $force_shortcode );
		$llm_elements = isset( $llm['elementor']['elements'] ) && is_array( $llm['elementor']['elements'] ) ? $llm['elementor']['elements'] : array();
		$elements = $this->elementor_builder->build_elements( $template, $instructions, $llm_elements );

		return array(
			'files'       => $files,
			'elementor'   => array(
				'elements'     => $elements,
				'post_content' => $this->elementor_builder->render_post_content( $elements ),
			),
			'agent_notes' => isset( $llm['agent_notes'] ) ? sanitize_textarea_field( (string) $llm['agent_notes'] ) : '',
			'llm_used'    => ! empty( $llm['success'] ),
			'llm_error'   => isset( $llm['error'] ) ? (string) $llm['error'] : '',
		);
	}

	private function fallback_files( $template, $instructions, $force_shortcode ) {
		$type = isset( $template['output_mode'] ) ? sanitize_key( (string) $template['output_mode'] ) : 'shortcode';
		if ( 'admin_snippet' === $type && ! $force_shortcode ) {
			return $this->admin_files( $template, $instructions );
		}
		return $this->frontend_files( $template, $instructions );
	}

	private function generate_with_llm( $template, $instructions, $force_shortcode ) {
		if ( ! $this->openai_client || ! method_exists( $this->openai_client, 'generate' ) || ! $this->auth_manager ) {
			return array( 'success' => false, 'error' => 'LLM dependencies are not loaded.' );
		}

		$auth_mode = method_exists( $this->auth_manager, 'get_mode' ) ? (string) $this->auth_manager->get_mode() : 'api_key';
		$creds     = method_exists( $this->auth_manager, 'get_credentials' ) ? (array) $this->auth_manager->get_credentials() : array();
		$model     = $this->model_router && method_exists( $this->model_router, 'route_for_founder_agent' )
			? (string) $this->model_router->route_for_founder_agent()
			: ( $this->model_router && method_exists( $this->model_router, 'route_for_agent' ) ? (string) $this->model_router->route_for_agent() : 'gpt-5.4-mini' );

		$result = $this->openai_client->generate(
			$model,
			$this->build_llm_input( $template, $instructions, $force_shortcode ),
			$this->build_llm_instructions(),
			$auth_mode,
			$creds,
			90
		);
		if ( empty( $result['success'] ) || empty( $result['answer'] ) ) {
			return array(
				'success' => false,
				'error'   => isset( $result['error'] ) ? (string) $result['error'] : 'LLM returned no answer.',
			);
		}

		$parsed = $this->parse_json_answer( (string) $result['answer'] );
		if ( ! is_array( $parsed ) ) {
			return array( 'success' => false, 'error' => 'LLM returned non-JSON template payload.' );
		}
		$parsed['success'] = true;
		return $parsed;
	}

	private function build_llm_instructions() {
		return 'You are Niwa Template Builder. Return only valid JSON. Build production-ready WordPress/Elementor template artifacts from the provided template card and founder instructions. Required JSON shape: {"files":[{"name":"template.html","content":"..."},{"name":"style.css","content":"..."},{"name":"script.js","content":"..."}],"elementor":{"elements":[Elementor JSON elements]},"agent_notes":"short Serbian/English note for Niwa about how to use/adapt this template"}. For admin snippets, files must include main.php. For Elementor elements use editable containers/widgets with id, elType, settings, elements; widget nodes need widgetType. Never return widgetType "html" for Elementor output unless the founder explicitly asks for raw HTML. Prefer native Elementor widgets such as heading, text-editor, button, image, icon-list, toggle, tabs, form-compatible controls, and Niwa custom widget settings. Use site_design_context and current_settings colors as the design source of truth; do not hardcode an unrelated palette, and keep buttons readable against the active theme. Do not include external scripts, dangerous PHP, tracking code, secrets, or prose outside JSON.';
	}

	private function build_llm_input( $template, $instructions, $force_shortcode ) {
		$payload = array(
			'template' => array(
				'id'               => isset( $template['id'] ) ? intval( $template['id'] ) : 0,
				'title'            => isset( $template['title'] ) ? (string) $template['title'] : '',
				'type'             => isset( $template['type'] ) ? (string) $template['type'] : '',
				'output_mode'      => isset( $template['output_mode'] ) ? (string) $template['output_mode'] : '',
				'subtitle'         => isset( $template['subtitle'] ) ? (string) $template['subtitle'] : '',
				'implementation_prompt' => isset( $template['prompt'] ) ? (string) $template['prompt'] : '',
				'agent_prompt'     => isset( $template['agent_prompt'] ) ? (string) $template['agent_prompt'] : '',
				'elementor_schema' => isset( $template['elementor_schema'] ) && is_array( $template['elementor_schema'] ) ? $template['elementor_schema'] : array(),
				'manifest'         => isset( $template['manifest'] ) && is_array( $template['manifest'] ) ? $template['manifest'] : array(),
			),
			'founder_instructions' => (string) $instructions,
			'force_shortcode'      => (bool) $force_shortcode,
			'site_design_context'  => $this->design_context_config(),
			'runtime_contract'     => 'If Elementor is active, Niwa may insert elementor.elements directly into _elementor_data; otherwise it publishes files as shortcode snippet.',
		);
		return wp_json_encode( $payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
	}

	private function parse_json_answer( $answer ) {
		$answer = trim( (string) $answer );
		if ( '' === $answer ) {
			return null;
		}
		if ( preg_match( '/```(?:json)?\s*(.*?)```/is', $answer, $m ) ) {
			$answer = trim( $m[1] );
		}
		$decoded = json_decode( $answer, true );
		if ( is_array( $decoded ) ) {
			return $decoded;
		}
		$start = strpos( $answer, '{' );
		$end   = strrpos( $answer, '}' );
		if ( false !== $start && false !== $end && $end > $start ) {
			$decoded = json_decode( substr( $answer, $start, $end - $start + 1 ), true );
			return is_array( $decoded ) ? $decoded : null;
		}
		return null;
	}

	private function design_context_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 normalize_files( $files ) {
		$clean = array();
		foreach ( $files as $file ) {
			if ( ! is_array( $file ) ) {
				continue;
			}
			$name = isset( $file['name'] ) ? sanitize_file_name( (string) $file['name'] ) : '';
			if ( '' === $name ) {
				continue;
			}
			$clean[] = array(
				'name'    => $name,
				'content' => isset( $file['content'] ) ? (string) $file['content'] : '',
			);
		}
		return $clean;
	}

	public function generate_elementor_widget_files( $template, $instructions = '', $snippet_id = 0 ) {
		$snippet_id = max( 1, intval( $snippet_id ) );
		$config     = $this->elementor_widget_config( $template, $instructions, $snippet_id );
		$class_name = 'Niwa_AI_Template_Widget_' . $snippet_id;
		$widget_name = 'niwa_tpl_' . $snippet_id;
		$title      = isset( $config['title'] ) ? (string) $config['title'] : 'Niwa Template Widget';
		$version    = '1.0.' . $snippet_id;

		$main_php = '<?php' . "\n"
			. "if ( ! defined( 'ABSPATH' ) ) { exit; }\n\n"
			. "function niwa_template_widget_register_assets_{$snippet_id}() {\n"
			. "\twp_register_style( 'niwa-template-widget-style-{$snippet_id}', content_url( 'niwa-snippets/prod/snippet-{$snippet_id}/style.css' ), array(), '{$version}' );\n"
			. "\twp_register_script( 'niwa-template-widget-script-{$snippet_id}', content_url( 'niwa-snippets/prod/snippet-{$snippet_id}/script.js' ), array( 'elementor-frontend' ), '{$version}', true );\n"
			. "}\n"
			. "add_action( 'wp_enqueue_scripts', 'niwa_template_widget_register_assets_{$snippet_id}' );\n"
			. "add_action( 'elementor/frontend/after_register_styles', 'niwa_template_widget_register_assets_{$snippet_id}' );\n"
			. "add_action( 'elementor/frontend/after_register_scripts', 'niwa_template_widget_register_assets_{$snippet_id}' );\n\n"
			. "function niwa_template_widget_register_{$snippet_id}( \$widgets_manager ) {\n"
			. "\trequire_once __DIR__ . '/widget.php';\n"
			. "\tif ( class_exists( '{$class_name}' ) ) {\n"
			. "\t\t\$widgets_manager->register( new \\{$class_name}() );\n"
			. "\t}\n"
			. "}\n"
			. "add_action( 'elementor/widgets/register', 'niwa_template_widget_register_{$snippet_id}' );\n";

		$widget_php = '<?php' . "\n"
			. "if ( ! defined( 'ABSPATH' ) ) { exit; }\n\n"
			. "class {$class_name} extends \\Niwa_AI_Elementor_Template_Widget_Base {\n"
			. "\tpublic function get_name() { return '{$widget_name}'; }\n"
			. "\tpublic function get_title() { return esc_html__( " . var_export( $title, true ) . ", 'niwa-ai' ); }\n"
			. "\tpublic function get_icon() { return 'eicon-code'; }\n"
			. "\tprotected function niwa_snippet_id() { return {$snippet_id}; }\n"
			. "\tprotected function niwa_template_config() { return " . var_export( $config, true ) . "; }\n"
			. "}\n";

		return array(
			array(
				'name'    => 'main.php',
				'content' => $main_php,
			),
			array(
				'name'    => 'widget.php',
				'content' => $widget_php,
			),
			array(
				'name'    => 'style.css',
				'content' => $this->elementor_widget_css(),
			),
			array(
				'name'    => 'script.js',
				'content' => $this->elementor_widget_js(),
			),
			array(
				'name'    => 'widget.json',
				'content' => wp_json_encode(
					array(
						'class'       => $class_name,
						'widget_name' => $widget_name,
						'config'      => $config,
					),
					JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT
				),
			),
		);
	}

	public function elementor_widget_settings_for_template( $template, $instructions = '' ) {
		$config   = $this->elementor_widget_config( $template, $instructions, 1 );
		$defaults = isset( $config['defaults'] ) && is_array( $config['defaults'] ) ? $config['defaults'] : array();
		$settings = array(
			'eyebrow'             => isset( $defaults['eyebrow'] ) ? (string) $defaults['eyebrow'] : 'Explore',
			'title'               => isset( $defaults['title'] ) ? (string) $defaults['title'] : '',
			'intro'               => isset( $defaults['intro'] ) ? (string) $defaults['intro'] : '',
			'cta_text'            => isset( $defaults['cta_text'] ) ? (string) $defaults['cta_text'] : 'Learn more',
			'cta_url'             => array( 'url' => isset( $defaults['cta_url'] ) ? (string) $defaults['cta_url'] : '#' ),
			'background_color'    => isset( $config['background_color'] ) ? (string) $config['background_color'] : '#07100d',
			'text_color'          => isset( $config['text_color'] ) ? (string) $config['text_color'] : '#f8fafc',
			'accent_color'        => isset( $config['accent_color'] ) ? (string) $config['accent_color'] : '#d6b46a',
			'card_background'     => isset( $config['card_background'] ) ? (string) $config['card_background'] : '#ffffff',
			'card_text_color'      => isset( $config['card_text_color'] ) ? (string) $config['card_text_color'] : '#111827',
			'muted_color'          => isset( $config['muted_color'] ) ? (string) $config['muted_color'] : '#64748b',
			'button_background'   => isset( $config['button_background'] ) ? (string) $config['button_background'] : '#d6b46a',
			'button_text_color'   => isset( $config['button_text_color'] ) ? (string) $config['button_text_color'] : '#07100d',
			'selected_card_background' => isset( $config['selected_card_background'] ) ? (string) $config['selected_card_background'] : '#07100d',
			'selected_card_text_color' => isset( $config['selected_card_text_color'] ) ? (string) $config['selected_card_text_color'] : '#ffffff',
		);
		$kind = isset( $config['kind'] ) ? (string) $config['kind'] : '';
		if ( in_array( $kind, array( 'image_reveal_menu', 'team_accordion', 'product_finder_quiz', 'habit_tracker' ), true ) ) {
			$settings['items'] = array();
			foreach ( isset( $defaults['items'] ) && is_array( $defaults['items'] ) ? $defaults['items'] : array() as $item ) {
				$settings['items'][] = array(
					'_id'              => $this->elementor_repeater_id(),
					'item_label'       => isset( $item['label'] ) ? (string) $item['label'] : 'Item',
					'item_description' => isset( $item['description'] ) ? (string) $item['description'] : '',
					'item_image'       => array( 'url' => isset( $item['image_url'] ) ? (string) $item['image_url'] : '' ),
				);
			}
		}
		if ( 'testimonial_carousel' === $kind ) {
			$settings['testimonials'] = array();
			foreach ( isset( $defaults['items'] ) && is_array( $defaults['items'] ) ? $defaults['items'] : array() as $item ) {
				$settings['testimonials'][] = array(
					'_id'                 => $this->elementor_repeater_id(),
					'testimonial_content' => isset( $item['content'] ) ? (string) $item['content'] : '',
					'testimonial_name'    => isset( $item['name'] ) ? (string) $item['name'] : 'Customer',
					'testimonial_role'    => isset( $item['role'] ) ? (string) $item['role'] : 'Verified customer',
					'testimonial_rating'  => isset( $item['rating'] ) ? intval( $item['rating'] ) : 5,
				);
			}
		}
		if ( 'pricing_cards' === $kind ) {
			$settings['plans'] = array();
			foreach ( isset( $defaults['plans'] ) && is_array( $defaults['plans'] ) ? $defaults['plans'] : array() as $plan ) {
				$settings['plans'][] = array(
					'_id'              => $this->elementor_repeater_id(),
					'plan_title'       => isset( $plan['title'] ) ? (string) $plan['title'] : 'Plan',
					'plan_price'       => isset( $plan['price'] ) ? (string) $plan['price'] : '',
					'plan_features'    => isset( $plan['features'] ) ? (string) $plan['features'] : '',
					'plan_button'      => isset( $plan['button'] ) ? (string) $plan['button'] : __( 'Choose plan', 'niwa-ai' ),
					'plan_highlighted' => ! empty( $plan['highlighted'] ) ? 'yes' : '',
				);
			}
		}
		if ( 'quote_calculator' === $kind ) {
			$settings['quote_unit_price'] = isset( $defaults['quote_unit_price'] ) ? intval( $defaults['quote_unit_price'] ) : 80;
			$settings['quote_quantity_min'] = isset( $defaults['quote_quantity_min'] ) ? intval( $defaults['quote_quantity_min'] ) : 1;
			$settings['quote_quantity_max'] = isset( $defaults['quote_quantity_max'] ) ? intval( $defaults['quote_quantity_max'] ) : 12;
			$settings['quote_quantity_default'] = isset( $defaults['quote_quantity_default'] ) ? intval( $defaults['quote_quantity_default'] ) : 4;
			$settings['quote_currency'] = isset( $defaults['quote_currency'] ) ? (string) $defaults['quote_currency'] : '$';
		}
		return $settings;
	}

	public function generate_elementor_widget_settings( $template, $instructions = '' ) {
		$settings = $this->elementor_widget_settings_for_template( $template, $instructions );
		if ( '' === trim( (string) $instructions ) || ! $this->openai_client || ! method_exists( $this->openai_client, 'generate' ) || ! $this->auth_manager ) {
			return array(
				'settings' => $settings,
				'llm_used' => false,
				'error'    => '',
			);
		}

		$auth_mode = method_exists( $this->auth_manager, 'get_mode' ) ? (string) $this->auth_manager->get_mode() : 'api_key';
		$creds     = method_exists( $this->auth_manager, 'get_credentials' ) ? (array) $this->auth_manager->get_credentials() : array();
		$model     = $this->model_router && method_exists( $this->model_router, 'route_for_founder_agent' )
			? (string) $this->model_router->route_for_founder_agent()
			: ( $this->model_router && method_exists( $this->model_router, 'route_for_agent' ) ? (string) $this->model_router->route_for_agent() : 'gpt-5.4-mini' );

		$payload = array(
			'template'         => array(
				'title'            => isset( $template['title'] ) ? (string) $template['title'] : '',
				'subtitle'         => isset( $template['subtitle'] ) ? (string) $template['subtitle'] : '',
				'prompt'           => isset( $template['prompt'] ) ? (string) $template['prompt'] : '',
				'agent_prompt'     => isset( $template['agent_prompt'] ) ? (string) $template['agent_prompt'] : '',
				'elementor_schema' => isset( $template['elementor_schema'] ) && is_array( $template['elementor_schema'] ) ? $template['elementor_schema'] : array(),
			),
			'founder_instructions' => (string) $instructions,
			'current_settings'     => $settings,
			'site_design_context'  => $this->design_context_config(),
			'contract'             => 'Return only JSON with {"settings":{...}}. Use only existing keys from current_settings. Keep site colors, typography mood, contrast, and button readability from site_design_context/current_settings. Do not return HTML, CSS, JS, PHP, or prose.',
		);

		$result = $this->openai_client->generate(
			$model,
			wp_json_encode( $payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ),
			'Adapt a Niwa native Elementor widget instance. Keep the widget editable by changing settings only. Inherit the active site design language, use the provided design colors, and return strict JSON only.',
			$auth_mode,
			$creds,
			45
		);
		if ( empty( $result['success'] ) || empty( $result['answer'] ) ) {
			return array(
				'settings' => $settings,
				'llm_used' => false,
				'error'    => isset( $result['error'] ) ? (string) $result['error'] : 'LLM returned no widget settings.',
			);
		}
		$parsed = $this->parse_json_answer( (string) $result['answer'] );
		if ( ! is_array( $parsed ) || empty( $parsed['settings'] ) || ! is_array( $parsed['settings'] ) ) {
			return array(
				'settings' => $settings,
				'llm_used' => false,
				'error'    => 'LLM returned invalid widget settings JSON.',
			);
		}
		return array(
			'settings' => $this->merge_elementor_widget_settings( $settings, $parsed['settings'] ),
			'llm_used' => true,
			'error'    => '',
		);
	}

	private function merge_elementor_widget_settings( $base, $candidate ) {
		$merged = $base;
		foreach ( array( 'eyebrow', 'title', 'intro', 'cta_text', 'background_color', 'text_color', 'accent_color', 'card_background', 'card_text_color', 'muted_color', 'button_background', 'button_text_color', 'selected_card_background', 'selected_card_text_color', 'quote_currency' ) as $key ) {
			if ( isset( $candidate[ $key ] ) && is_scalar( $candidate[ $key ] ) && '' !== trim( (string) $candidate[ $key ] ) ) {
				$merged[ $key ] = sanitize_textarea_field( (string) $candidate[ $key ] );
			}
		}
		foreach ( array( 'quote_unit_price', 'quote_quantity_min', 'quote_quantity_max', 'quote_quantity_default' ) as $key ) {
			if ( isset( $candidate[ $key ] ) && is_numeric( $candidate[ $key ] ) ) {
				$merged[ $key ] = max( 1, intval( $candidate[ $key ] ) );
			}
		}
		if ( isset( $candidate['cta_url'] ) ) {
			if ( is_array( $candidate['cta_url'] ) && isset( $candidate['cta_url']['url'] ) ) {
				$merged['cta_url'] = array( 'url' => esc_url_raw( (string) $candidate['cta_url']['url'] ) );
			} elseif ( is_scalar( $candidate['cta_url'] ) ) {
				$merged['cta_url'] = array( 'url' => esc_url_raw( (string) $candidate['cta_url'] ) );
			}
		}
		if ( isset( $candidate['items'] ) && is_array( $candidate['items'] ) && isset( $base['items'] ) ) {
			$merged['items'] = array();
			foreach ( array_slice( $candidate['items'], 0, 8 ) as $item ) {
				if ( ! is_array( $item ) ) {
					continue;
				}
				$image_url = '';
				if ( isset( $item['item_image']['url'] ) ) {
					$image_url = (string) $item['item_image']['url'];
				} elseif ( isset( $item['image_url'] ) ) {
					$image_url = (string) $item['image_url'];
				}
				$merged['items'][] = array(
					'_id'              => $this->elementor_repeater_id(),
					'item_label'       => sanitize_text_field( isset( $item['item_label'] ) ? (string) $item['item_label'] : ( isset( $item['label'] ) ? (string) $item['label'] : 'Item' ) ),
					'item_description' => sanitize_textarea_field( isset( $item['item_description'] ) ? (string) $item['item_description'] : ( isset( $item['description'] ) ? (string) $item['description'] : '' ) ),
					'item_image'       => array( 'url' => esc_url_raw( $image_url ) ),
				);
			}
		}
		if ( isset( $candidate['testimonials'] ) && is_array( $candidate['testimonials'] ) && isset( $base['testimonials'] ) ) {
			$merged['testimonials'] = array();
			foreach ( array_slice( $candidate['testimonials'], 0, 8 ) as $item ) {
				if ( ! is_array( $item ) ) {
					continue;
				}
				$merged['testimonials'][] = array(
					'_id'                 => $this->elementor_repeater_id(),
					'testimonial_content' => sanitize_textarea_field( isset( $item['testimonial_content'] ) ? (string) $item['testimonial_content'] : ( isset( $item['content'] ) ? (string) $item['content'] : '' ) ),
					'testimonial_name'    => sanitize_text_field( isset( $item['testimonial_name'] ) ? (string) $item['testimonial_name'] : ( isset( $item['name'] ) ? (string) $item['name'] : 'Customer' ) ),
					'testimonial_role'    => sanitize_text_field( isset( $item['testimonial_role'] ) ? (string) $item['testimonial_role'] : ( isset( $item['role'] ) ? (string) $item['role'] : 'Verified customer' ) ),
					'testimonial_rating'  => max( 1, min( 5, intval( isset( $item['testimonial_rating'] ) ? $item['testimonial_rating'] : ( isset( $item['rating'] ) ? $item['rating'] : 5 ) ) ) ),
				);
			}
		}
		if ( isset( $candidate['plans'] ) && is_array( $candidate['plans'] ) && isset( $base['plans'] ) ) {
			$merged['plans'] = array();
			foreach ( array_slice( $candidate['plans'], 0, 6 ) as $plan ) {
				if ( ! is_array( $plan ) ) {
					continue;
				}
				$merged['plans'][] = array(
					'_id'              => $this->elementor_repeater_id(),
					'plan_title'       => sanitize_text_field( isset( $plan['plan_title'] ) ? (string) $plan['plan_title'] : ( isset( $plan['title'] ) ? (string) $plan['title'] : 'Plan' ) ),
					'plan_price'       => sanitize_text_field( isset( $plan['plan_price'] ) ? (string) $plan['plan_price'] : ( isset( $plan['price'] ) ? (string) $plan['price'] : '' ) ),
					'plan_features'    => sanitize_textarea_field( isset( $plan['plan_features'] ) ? (string) $plan['plan_features'] : ( isset( $plan['features'] ) ? (string) $plan['features'] : '' ) ),
					'plan_button'      => sanitize_text_field( isset( $plan['plan_button'] ) ? (string) $plan['plan_button'] : ( isset( $plan['button'] ) ? (string) $plan['button'] : __( 'Choose plan', 'niwa-ai' ) ) ),
					'plan_highlighted' => ! empty( $plan['plan_highlighted'] ) || ! empty( $plan['highlighted'] ) ? 'yes' : '',
				);
			}
		}
		return $merged;
	}

	private function elementor_widget_config( $template, $instructions, $snippet_id ) {
		$schema = isset( $template['elementor_schema'] ) && is_array( $template['elementor_schema'] ) ? $template['elementor_schema'] : array();
		$title  = isset( $schema['title'] ) && '' !== trim( (string) $schema['title'] ) ? (string) $schema['title'] : ( isset( $template['title'] ) ? (string) $template['title'] : 'Niwa Template Widget' );
		$kind   = isset( $schema['kind'] ) ? sanitize_key( (string) $schema['kind'] ) : $this->infer_elementor_widget_kind( $template );
		$intro  = isset( $schema['intro'] ) && '' !== trim( (string) $schema['intro'] ) ? (string) $schema['intro'] : ( isset( $template['subtitle'] ) ? (string) $template['subtitle'] : '' );
		$items  = isset( $schema['items'] ) && is_array( $schema['items'] ) ? $schema['items'] : array();
		$plans  = isset( $schema['plans'] ) && is_array( $schema['plans'] ) ? $schema['plans'] : array();

		if ( empty( $items ) && 'team_accordion' === $kind ) {
			$items = array(
				array( 'label' => 'Strategy Lead', 'description' => 'Owns positioning, messaging, and launch decisions.', 'image_url' => 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?auto=format&fit=crop&w=1200&q=80' ),
				array( 'label' => 'Design Lead', 'description' => 'Shapes the visual system and responsive details.', 'image_url' => 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?auto=format&fit=crop&w=1200&q=80' ),
				array( 'label' => 'Growth Lead', 'description' => 'Connects the section to conversion and next actions.', 'image_url' => 'https://images.unsplash.com/photo-1531123897727-8f129e1688ce?auto=format&fit=crop&w=1200&q=80' ),
			);
		}
		if ( empty( $items ) && 'testimonial_carousel' === $kind ) {
			$items = array(
				array( 'content' => 'Clear, fast and useful from the first session.', 'name' => 'Customer', 'role' => 'Verified customer', 'rating' => 5 ),
				array( 'content' => 'The page finally explains the offer properly.', 'name' => 'Founder', 'role' => 'Founder', 'rating' => 5 ),
				array( 'content' => 'The section matched our offer and tone.', 'name' => 'Operator', 'role' => 'Operator', 'rating' => 5 ),
			);
		}
		if ( empty( $items ) && 'image_reveal_menu' === $kind ) {
			$items = array(
				array( 'label' => 'Fresh Truffles', 'description' => 'Seasonal black and white truffles prepared for premium dishes.', 'image_url' => 'https://images.unsplash.com/photo-1604908176997-125f25cc6f3d?auto=format&fit=crop&w=1200&q=80' ),
				array( 'label' => 'Truffle Pantry', 'description' => 'Oils, creams, salts, and everyday finishing accents.', 'image_url' => 'https://images.unsplash.com/photo-1556911220-bff31c812dba?auto=format&fit=crop&w=1200&q=80' ),
				array( 'label' => 'Gift Sets', 'description' => 'Curated gourmet bundles with a polished retail feel.', 'image_url' => 'https://images.unsplash.com/photo-1513885535751-8b9238bd345a?auto=format&fit=crop&w=1200&q=80' ),
				array( 'label' => 'Recipe Pairings', 'description' => 'Practical serving ideas for pasta, eggs, risotto, and cheese.', 'image_url' => 'https://images.unsplash.com/photo-1551218808-94e220e084d2?auto=format&fit=crop&w=1200&q=80' ),
			);
		}
		if ( empty( $items ) && 'product_finder_quiz' === $kind ) {
			$items = array(
				array( 'label' => 'Gift experience', 'description' => 'Polished recommendation for visitors buying for someone else.', 'image_url' => '' ),
				array( 'label' => 'Everyday pantry', 'description' => 'Practical recommendation for repeat use and simple replenishment.', 'image_url' => '' ),
				array( 'label' => 'Chef-grade ingredient', 'description' => 'Premium recommendation for confident cooks or expert buyers.', 'image_url' => '' ),
			);
		}
		if ( empty( $items ) && 'habit_tracker' === $kind ) {
			$items = array(
				array( 'label' => 'Plan', 'description' => 'Map the next action.', 'image_url' => '' ),
				array( 'label' => 'Create', 'description' => 'Produce the deliverable.', 'image_url' => '' ),
				array( 'label' => 'Publish', 'description' => 'Ship the update.', 'image_url' => '' ),
				array( 'label' => 'Follow up', 'description' => 'Close the loop.', 'image_url' => '' ),
				array( 'label' => 'Review', 'description' => 'Check quality and results.', 'image_url' => '' ),
			);
		}
		if ( empty( $plans ) && 'pricing_cards' === $kind ) {
			$plans = array(
				array( 'title' => 'Starter', 'price' => '$49', 'features' => "Fast launch\nCore sections\nBasic support" ),
				array( 'title' => 'Growth', 'price' => '$149', 'features' => "Custom layout\nAutomations\nPriority support", 'highlighted' => true ),
				array( 'title' => 'Scale', 'price' => 'Custom', 'features' => "Advanced workflows\nIntegrations\nDedicated support" ),
			);
		}

		if ( in_array( $kind, array( 'team_accordion', 'product_finder_quiz', 'habit_tracker' ), true ) ) {
			$items = array_map(
				function ( $item ) {
					return array(
						'label'       => isset( $item['label'] ) ? (string) $item['label'] : ( isset( $item['name'] ) ? (string) $item['name'] : 'Team member' ),
						'description' => isset( $item['description'] ) ? (string) $item['description'] : ( isset( $item['role'] ) ? (string) $item['role'] : '' ),
						'image_url'   => isset( $item['image_url'] ) ? (string) $item['image_url'] : '',
					);
				},
				$items
			);
		}

		$config = array(
			'snippet_id'          => intval( $snippet_id ),
			'kind'                => $kind,
			'title'               => $title,
			'background_color'    => in_array( $kind, array( 'testimonial_carousel', 'pricing_cards', 'product_finder_quiz', 'habit_tracker' ), true ) ? '#f8fafc' : '#07100d',
			'text_color'          => in_array( $kind, array( 'testimonial_carousel', 'pricing_cards', 'product_finder_quiz', 'habit_tracker' ), true ) ? '#111827' : '#f8fafc',
			'accent_color'        => isset( $schema['accent'] ) && '' !== trim( (string) $schema['accent'] ) ? (string) $schema['accent'] : '#d6b46a',
			'card_background'     => '#ffffff',
			'card_text_color'     => '#111827',
			'muted_color'         => '#64748b',
			'button_background'   => '#d6b46a',
			'button_text_color'   => '#07100d',
			'selected_card_background' => '#07100d',
			'selected_card_text_color' => '#ffffff',
			'defaults'            => array(
				'title'    => $title,
				'eyebrow'  => isset( $schema['eyebrow'] ) && '' !== trim( (string) $schema['eyebrow'] ) ? (string) $schema['eyebrow'] : ( 'team_accordion' === $kind || 'image_reveal_menu' === $kind ? 'Explore' : 'Elementor widget' ),
				'intro'    => $intro,
				'cta_text' => isset( $schema['cta_text'] ) && '' !== trim( (string) $schema['cta_text'] ) ? (string) $schema['cta_text'] : 'Learn more',
				'cta_url'  => isset( $schema['cta_url'] ) && '' !== trim( (string) $schema['cta_url'] ) ? (string) $schema['cta_url'] : '#',
				'items'    => array_values( $items ),
				'plans'    => array_values( $plans ),
				'quote_unit_price' => isset( $schema['quote_unit_price'] ) ? intval( $schema['quote_unit_price'] ) : 80,
				'quote_quantity_min' => isset( $schema['quote_quantity_min'] ) ? intval( $schema['quote_quantity_min'] ) : 1,
				'quote_quantity_max' => isset( $schema['quote_quantity_max'] ) ? intval( $schema['quote_quantity_max'] ) : 12,
				'quote_quantity_default' => isset( $schema['quote_quantity_default'] ) ? intval( $schema['quote_quantity_default'] ) : 4,
				'quote_currency' => isset( $schema['quote_currency'] ) && '' !== trim( (string) $schema['quote_currency'] ) ? (string) $schema['quote_currency'] : '$',
			),
		);
		if ( class_exists( 'Niwa_AI_Template_Design_Context' ) ) {
			$config = ( new Niwa_AI_Template_Design_Context() )->apply_to_widget_config( $config );
		}
		return $config;
	}

	private function infer_elementor_widget_kind( $template ) {
		$title = strtolower( isset( $template['title'] ) ? (string) $template['title'] : '' );
		if ( false !== strpos( $title, 'team' ) || false !== strpos( $title, 'accordion' ) ) {
			return 'team_accordion';
		}
		if ( false !== strpos( $title, 'testimonial' ) || false !== strpos( $title, 'carousel' ) ) {
			return 'testimonial_carousel';
		}
		if ( false !== strpos( $title, 'pricing' ) || false !== strpos( $title, 'cards' ) ) {
			return 'pricing_cards';
		}
		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 ( false !== strpos( $title, 'habit tracker' ) || false !== strpos( $title, 'habit' ) ) {
			return 'habit_tracker';
		}
		return 'image_reveal_menu';
	}

	private function elementor_repeater_id() {
		return substr( md5( wp_generate_uuid4() ), 0, 7 );
	}

	private function elementor_widget_css() {
		return <<<'CSS'
.niwa-native-widget{--niwa-native-bg:#07100d;--niwa-native-text:#f8fafc;--niwa-native-accent:#d6b46a;--niwa-native-card:#fff;--niwa-native-card-text:#111827;--niwa-native-muted:#64748b;--niwa-native-button-bg:#d6b46a;--niwa-native-button-text:#07100d;--niwa-native-selected-card:#07100d;--niwa-native-selected-text:#fff;box-sizing:border-box;width:100%;padding:clamp(56px,8vw,96px) clamp(18px,5vw,72px);background:var(--niwa-native-bg);color:var(--niwa-native-text);overflow:hidden}
.niwa-native-widget *{box-sizing:border-box}
.niwa-native-widget button{font:inherit;appearance:none!important;box-sizing:border-box;min-width:0!important;line-height:1.1!important}
.niwa-native-widget__intro{max-width:900px;margin:0 auto 34px;text-align:left}
.niwa-native-widget__intro>span{display:inline-flex;margin:0 0 14px;color:var(--niwa-native-accent);font-size:12px;font-weight:800;text-transform:uppercase;letter-spacing:.12em}
.niwa-native-widget h2{margin:0 0 16px;color:inherit;font-size:clamp(34px,5vw,70px);line-height:.98;letter-spacing:0}
.niwa-native-widget p{color:var(--niwa-native-muted);line-height:1.65}
.niwa-native-widget__cta{display:inline-flex;align-items:center;justify-content:center;min-height:44px;margin-top:8px;padding:0 18px;border:1px solid color-mix(in srgb,var(--niwa-native-accent) 60%,transparent);border-radius:6px;background:var(--niwa-native-button-bg)!important;color:var(--niwa-native-button-text)!important;text-decoration:none!important;font-weight:800}
.niwa-reveal-native__interactive{display:grid;grid-template-columns:minmax(260px,.85fr) minmax(360px,1.15fr);gap:28px;align-items:stretch;max-width:1180px;margin:0 auto}
.niwa-reveal-native__items{display:flex;flex-direction:column;border-top:1px solid color-mix(in srgb,var(--niwa-native-text) 18%,transparent)}
.niwa-reveal-native__item{display:grid!important;grid-template-columns:42px 1fr;width:100%;gap:12px;padding:18px 0!important;border:0!important;border-bottom:1px solid color-mix(in srgb,var(--niwa-native-text) 18%,transparent)!important;border-radius:0!important;background:transparent!important;color:color-mix(in srgb,var(--niwa-native-text) 72%,transparent)!important;text-align:left!important;cursor:pointer!important;transition:background .28s ease,color .28s ease}
.niwa-reveal-native__item span{color:var(--niwa-native-accent);font-size:12px;font-weight:800}
.niwa-reveal-native__item strong{display:block;color:inherit;font-size:18px;line-height:1.15}
.niwa-reveal-native__item em{display:block;grid-column:2;margin-top:7px;color:color-mix(in srgb,var(--niwa-native-text) 58%,transparent);font-size:13px;font-style:normal;line-height:1.45}
.niwa-reveal-native__item:hover,.niwa-reveal-native__item:focus-visible,.niwa-reveal-native__item.is-active{background:color-mix(in srgb,var(--niwa-native-accent) 12%,transparent)!important;color:var(--niwa-native-text)!important;outline:none!important}
.niwa-reveal-native__stage{position:relative;min-height:520px;border-radius:8px;overflow:hidden;background:var(--niwa-native-selected-card);box-shadow:0 24px 70px rgba(0,0,0,.28)}
.niwa-reveal-native__image{position:absolute;inset:0;margin:0;background-color:#10231d;background-size:cover;background-position:center;isolation:isolate;opacity:0;transform:scale(1.05);transition:opacity .45s ease,transform .75s ease}
.niwa-reveal-native__image:before{content:"";position:absolute;inset:0;z-index:-1;background:radial-gradient(circle at 24% 22%,color-mix(in srgb,var(--niwa-native-accent) 34%,transparent),transparent 26%),radial-gradient(circle at 74% 44%,color-mix(in srgb,var(--niwa-native-text) 18%,transparent),transparent 28%),linear-gradient(135deg,color-mix(in srgb,var(--niwa-native-bg) 76%,var(--niwa-native-accent)),var(--niwa-native-bg) 55%,var(--niwa-native-selected-card));opacity:.92}
.niwa-reveal-native__image.is-active{opacity:1;transform:scale(1)}
.niwa-reveal-native__image figcaption{position:absolute;z-index:1;left:22px;right:22px;bottom:22px;color:var(--niwa-native-text);font-size:13px;font-weight:800;text-transform:uppercase;letter-spacing:.09em}
.niwa-team-native__cards{display:flex;gap:14px;max-width:1180px;min-height:520px;margin:0 auto}
.niwa-team-native__card{position:relative;flex:1;min-width:120px;display:flex;align-items:flex-end;border-radius:8px;overflow:hidden;background-color:var(--niwa-native-selected-card);background-size:cover;background-position:center;padding:24px;color:var(--niwa-native-text);cursor:pointer;isolation:isolate;transition:flex .65s cubic-bezier(.22,1,.36,1),transform .38s ease,filter .38s ease}
.niwa-team-native__card:before{content:"";position:absolute;inset:0;z-index:-1;background:radial-gradient(circle at 25% 20%,color-mix(in srgb,var(--niwa-native-accent) 30%,transparent),transparent 30%),linear-gradient(145deg,var(--niwa-native-selected-card),var(--niwa-native-bg));opacity:.88}
.niwa-team-native__card.is-active{flex:3;filter:saturate(1.05)}
.niwa-team-native__card:focus-visible{outline:3px solid var(--niwa-native-accent);outline-offset:3px}
.niwa-team-native__card>div{position:relative;z-index:1}
.niwa-team-native__card span{color:var(--niwa-native-accent);font-size:12px;font-weight:800}
.niwa-team-native__card h3{margin:8px 0 8px;color:var(--niwa-native-text);font-size:clamp(24px,3vw,42px);line-height:1}
.niwa-team-native__card p{max-height:0;margin:0;opacity:0;color:var(--niwa-native-muted);transition:max-height .52s ease,opacity .48s ease,margin .48s ease}
.niwa-team-native__card.is-active p{max-height:140px;margin-top:12px;opacity:1}
.niwa-testimonials-native__track,.niwa-pricing-native__grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px;max-width:1120px;margin:0 auto}
.niwa-native-widget--testimonial_carousel,.niwa-native-widget--pricing_cards{background:var(--niwa-native-bg);color:var(--niwa-native-text)}
.niwa-testimonials-native__track article,.niwa-pricing-native__grid article{padding:28px;border:1px solid color-mix(in srgb,var(--niwa-native-card-text) 12%,transparent);border-radius:8px;background:var(--niwa-native-card);color:var(--niwa-native-card-text);box-shadow:0 18px 50px rgba(15,23,42,.08);transition:transform .25s ease,background .25s ease,color .25s ease,border-color .25s ease}
.niwa-testimonials-native__track article{opacity:.72}
.niwa-testimonials-native__track article.is-active,.niwa-pricing-native__grid article.is-selected{background:var(--niwa-native-selected-card);color:var(--niwa-native-selected-text);border-color:var(--niwa-native-accent);opacity:1;transform:translateY(-8px)}
.niwa-testimonials-native__stars{color:var(--niwa-native-accent);font-size:18px;letter-spacing:3px}
.niwa-testimonials-native__track p,.niwa-pricing-native__grid p{color:inherit;opacity:.78}
.niwa-testimonials-native__track strong{display:block;color:inherit}
.niwa-testimonials-native__track span{display:block;margin-top:6px;color:inherit;opacity:.58;font-size:12px;text-transform:uppercase}
.niwa-testimonials-native__controls{display:flex;align-items:center;justify-content:center;gap:14px;margin-top:24px}
.niwa-testimonials-native__controls button{display:inline-grid!important;place-items:center!important;width:42px!important;height:42px!important;min-width:42px!important;aspect-ratio:1!important;padding:0!important;border:0!important;border-radius:999px!important;background:var(--niwa-native-selected-card)!important;color:var(--niwa-native-selected-text)!important;font-weight:900!important;cursor:pointer!important}
.niwa-testimonials-native__controls button:hover,.niwa-testimonials-native__controls button:focus-visible{background:var(--niwa-native-button-bg)!important;color:var(--niwa-native-button-text)!important;outline:none!important}
[data-niwa-pricing-output]{display:block;margin-top:14px;color:var(--niwa-native-muted);font-weight:800}
.niwa-pricing-native__grid h3{margin:0 0 14px;color:inherit;font-size:24px}
.niwa-pricing-native__grid strong{display:block;margin-bottom:18px;color:inherit;font-size:42px;line-height:1}
.niwa-pricing-native__grid ul{margin:0 0 18px;padding:0;list-style:none}
.niwa-pricing-native__grid li{padding:7px 0;border-bottom:1px solid rgba(100,116,139,.18);color:inherit;opacity:.82}
.niwa-pricing-native__grid button{display:inline-flex!important;align-items:center!important;justify-content:center!important;min-height:42px!important;padding:0 16px!important;border:0!important;border-radius:6px!important;background:var(--niwa-native-button-bg)!important;color:var(--niwa-native-button-text)!important;font-weight:800!important;cursor:pointer!important}
.niwa-pricing-native__grid button:hover,.niwa-pricing-native__grid button:focus-visible{background:var(--niwa-native-button-bg)!important;color:var(--niwa-native-button-text)!important;outline:2px solid color-mix(in srgb,var(--niwa-native-button-bg) 60%,transparent)!important;outline-offset:2px}
.niwa-product-quiz-native{display:grid;grid-template-columns:minmax(0,1fr) minmax(280px,420px);gap:22px;max-width:1120px;margin:0 auto;align-items:stretch}
.niwa-product-quiz-native__choices{display:grid;gap:12px}
.niwa-product-quiz-native__choices button{display:grid!important;grid-template-columns:42px 1fr;gap:12px;width:100%;min-height:92px;padding:18px!important;border:1px solid color-mix(in srgb,var(--niwa-native-accent) 32%,transparent)!important;border-radius:8px!important;background:var(--niwa-native-card)!important;color:var(--niwa-native-card-text)!important;text-align:left!important;cursor:pointer!important;transition:transform .22s ease,border-color .22s ease,background .22s ease}
.niwa-product-quiz-native__choices button.is-active,.niwa-product-quiz-native__choices button:hover,.niwa-product-quiz-native__choices button:focus-visible{border-color:var(--niwa-native-accent)!important;background:color-mix(in srgb,var(--niwa-native-accent) 15%,var(--niwa-native-card))!important;transform:translateY(-2px);outline:none!important}
.niwa-product-quiz-native__choices span{color:var(--niwa-native-accent);font-size:12px;font-weight:800}
.niwa-product-quiz-native__choices strong{display:block;color:var(--niwa-native-card-text);font-size:18px}
.niwa-product-quiz-native__choices em{grid-column:2;color:var(--niwa-native-muted);font-style:normal;line-height:1.45}
.niwa-product-quiz-native aside,.niwa-quote-native{padding:28px;border:1px solid color-mix(in srgb,var(--niwa-native-accent) 34%,transparent);border-radius:8px;background:var(--niwa-native-card);color:var(--niwa-native-card-text);box-shadow:0 24px 60px rgba(15,23,42,.1)}
.niwa-product-quiz-native aside small{color:var(--niwa-native-accent);font-size:12px;font-weight:800;text-transform:uppercase}
.niwa-product-quiz-native aside strong{display:block;margin:12px 0;color:var(--niwa-native-card-text);font-size:clamp(28px,4vw,44px);line-height:1}
.niwa-product-quiz-native aside p{color:var(--niwa-native-muted)}
.niwa-product-quiz-native aside a,.niwa-quote-native a{display:inline-flex;align-items:center;justify-content:center;min-height:44px;margin-top:12px;padding:0 18px;border-radius:6px;background:var(--niwa-native-button-bg)!important;color:var(--niwa-native-button-text)!important;text-decoration:none!important;font-weight:800}
.niwa-quote-native{max-width:720px;margin:0 auto}
.niwa-quote-native label{display:block;color:var(--niwa-native-card-text);font-weight:800}
.niwa-quote-native input[type=range]{display:block;width:100%;margin:16px 0 10px;accent-color:var(--niwa-native-accent)}
.niwa-quote-native label output{display:inline-flex;min-width:42px;min-height:32px;align-items:center;justify-content:center;border-radius:999px;background:var(--niwa-native-selected-card);color:var(--niwa-native-selected-text)}
.niwa-quote-native__total{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;margin-top:22px;padding-top:22px;border-top:1px solid color-mix(in srgb,var(--niwa-native-card-text) 14%,transparent)}
.niwa-quote-native__total span{color:var(--niwa-native-muted)}
.niwa-quote-native__total strong{color:var(--niwa-native-card-text);font-size:clamp(34px,6vw,58px);line-height:1}
.niwa-habit-native{display:grid;grid-template-columns:minmax(220px,300px) minmax(0,1fr);gap:22px;max-width:1120px;margin:0 auto}
.niwa-habit-native__stats{display:grid;align-content:start;gap:12px}
.niwa-habit-native__stats output,.niwa-habit-native__stats button{display:flex;align-items:center;min-height:54px;padding:0 18px;border:0;border-radius:999px;font-weight:900}
.niwa-habit-native__stats output:first-child{background:color-mix(in srgb,var(--niwa-native-accent) 18%,var(--niwa-native-card));color:var(--niwa-native-card-text)}
.niwa-habit-native__stats output:nth-child(2){background:var(--niwa-native-selected-card);color:var(--niwa-native-selected-text)}
.niwa-habit-native__stats button{justify-content:center;background:var(--niwa-native-button-bg)!important;color:var(--niwa-native-button-text)!important;cursor:pointer!important;text-transform:uppercase}
.niwa-habit-native__grid{display:grid;grid-template-columns:minmax(120px,1.1fr) repeat(7,minmax(38px,1fr));gap:8px;align-items:center;padding:18px;border:1px solid color-mix(in srgb,var(--niwa-native-card-text) 12%,transparent);border-radius:8px;background:var(--niwa-native-card);box-shadow:0 24px 60px rgba(15,23,42,.1);overflow:auto}
.niwa-habit-native__grid>strong{color:var(--niwa-native-muted);font-size:12px;text-align:center;text-transform:uppercase}
.niwa-habit-native__grid>b{color:var(--niwa-native-card-text);font-size:15px}
.niwa-habit-native__grid button{display:grid!important;place-items:center!important;width:100%!important;min-width:38px!important;aspect-ratio:1!important;padding:0!important;border:1px solid color-mix(in srgb,var(--niwa-native-card-text) 12%,transparent)!important;border-radius:8px!important;background:color-mix(in srgb,var(--niwa-native-card) 88%,var(--niwa-native-card-text))!important;cursor:pointer!important}
.niwa-habit-native__grid button span{width:12px;height:12px;border-radius:999px;background:transparent}
.niwa-habit-native__grid button.is-complete,.niwa-habit-native__grid button[aria-pressed=true]{border-color:var(--niwa-native-accent)!important;background:color-mix(in srgb,var(--niwa-native-accent) 18%,var(--niwa-native-card))!important}
.niwa-habit-native__grid button.is-complete span,.niwa-habit-native__grid button[aria-pressed=true] span{background:var(--niwa-native-accent)}
@media(max-width:900px){.niwa-reveal-native__interactive,.niwa-testimonials-native__track,.niwa-pricing-native__grid{grid-template-columns:1fr}.niwa-reveal-native__stage{min-height:360px}.niwa-team-native__cards{display:grid;grid-template-columns:1fr;min-height:0}.niwa-team-native__card,.niwa-team-native__card.is-active{min-height:230px;flex:auto}.niwa-testimonials-native__track article.is-active,.niwa-pricing-native__grid article.is-selected{transform:none}}
@media(max-width:900px){.niwa-product-quiz-native,.niwa-habit-native{grid-template-columns:1fr}.niwa-quote-native__total{display:block}.niwa-quote-native__total strong{display:block;margin-top:8px}}
@media(max-width:560px){.niwa-native-widget{padding:42px 18px}.niwa-reveal-native__item{grid-template-columns:34px 1fr}.niwa-reveal-native__stage{min-height:300px}.niwa-habit-native__grid{grid-template-columns:minmax(70px,.9fr) repeat(7,minmax(28px,1fr));gap:5px;padding:10px}.niwa-habit-native__grid>b{font-size:12px}.niwa-habit-native__grid>strong{font-size:9px}.niwa-habit-native__grid button{min-width:28px!important;border-radius:6px!important}.niwa-habit-native__grid button span{width:10px;height:10px}}
CSS;
	}

	private function elementor_widget_js() {
		return <<<'JS'
document.querySelectorAll('[data-niwa-kind="image_reveal_menu"]').forEach(function(root){var buttons=root.querySelectorAll('[data-niwa-reveal-index]');var panels=root.querySelectorAll('[data-niwa-reveal-panel]');function setActive(index){buttons.forEach(function(btn){var active=btn.getAttribute('data-niwa-reveal-index')===String(index);btn.classList.toggle('is-active',active);btn.setAttribute('aria-selected',active?'true':'false');});panels.forEach(function(panel){panel.classList.toggle('is-active',panel.getAttribute('data-niwa-reveal-panel')===String(index));});}buttons.forEach(function(btn){var index=btn.getAttribute('data-niwa-reveal-index');btn.addEventListener('mouseenter',function(){setActive(index);});btn.addEventListener('focus',function(){setActive(index);});btn.addEventListener('click',function(){setActive(index);});});});
document.querySelectorAll('[data-niwa-kind="team_accordion"]').forEach(function(root){var cards=root.querySelectorAll('[data-niwa-team-card]');function activate(card){cards.forEach(function(item){var active=item===card;item.classList.toggle('is-active',active);item.setAttribute('aria-expanded',active?'true':'false');});}cards.forEach(function(card){card.addEventListener('mouseenter',function(){activate(card);});card.addEventListener('focus',function(){activate(card);});card.addEventListener('click',function(){activate(card);});});});
document.querySelectorAll('[data-niwa-kind="testimonial_carousel"]').forEach(function(root){var slides=root.querySelectorAll('[data-niwa-testimonial-slide]');var output=root.querySelector('[data-niwa-testimonial-output]');var prev=root.querySelector('[data-niwa-testimonial-prev]');var next=root.querySelector('[data-niwa-testimonial-next]');var index=0;function show(nextIndex){if(!slides.length){return;}index=(nextIndex+slides.length)%slides.length;slides.forEach(function(slide,i){slide.classList.toggle('is-active',i===index);});if(output){output.textContent='Slide '+(index+1)+' of '+slides.length;}}if(prev){prev.addEventListener('click',function(){show(index-1);});}if(next){next.addEventListener('click',function(){show(index+1);});}slides.forEach(function(slide,i){slide.addEventListener('click',function(){show(i);});});show(index);});
document.querySelectorAll('[data-niwa-kind="pricing_cards"]').forEach(function(root){var cards=root.querySelectorAll('[data-niwa-plan]');var output=root.querySelector('[data-niwa-pricing-output]');cards.forEach(function(card){var btn=card.querySelector('[data-niwa-plan-select]');if(!btn){return;}btn.addEventListener('click',function(){cards.forEach(function(item){item.classList.remove('is-selected');});card.classList.add('is-selected');if(output){output.textContent=card.getAttribute('data-niwa-plan')+' selected.';}});});});
document.querySelectorAll('[data-niwa-product-quiz]').forEach(function(root){var choices=root.querySelectorAll('[data-niwa-product-choice]');var title=root.querySelector('[data-niwa-product-result-title]');var copy=root.querySelector('[data-niwa-product-result-copy]');choices.forEach(function(choice){choice.addEventListener('click',function(){choices.forEach(function(item){item.classList.remove('is-active');});choice.classList.add('is-active');if(title){title.textContent=choice.getAttribute('data-result-title')||choice.textContent.trim();}if(copy){copy.textContent=choice.getAttribute('data-result-copy')||'';}});});});
document.querySelectorAll('[data-niwa-quote-calc]').forEach(function(root){var qty=root.querySelector('[data-niwa-quote-qty]');var qtyOut=root.querySelector('[data-niwa-quote-qty-output]');var total=root.querySelector('[data-niwa-quote-total]');var unit=parseInt(root.getAttribute('data-unit-price')||'80',10);var currency=root.getAttribute('data-currency')||'$';function update(){if(!qty||!total){return;}var value=parseInt(qty.value||'1',10);if(qtyOut){qtyOut.textContent=String(value);}total.textContent=currency+String(value*unit);}if(qty){qty.addEventListener('input',update);update();}});
document.querySelectorAll('[data-niwa-habit-tracker]').forEach(function(root){var cells=root.querySelectorAll('[data-niwa-habit-cell]');var progress=root.querySelector('[data-niwa-habit-progress]');var streak=root.querySelector('[data-niwa-habit-streak]');var reset=root.querySelector('[data-niwa-habit-reset]');function update(){var complete=0;var days={};cells.forEach(function(cell){var active=cell.getAttribute('aria-pressed')==='true'||cell.classList.contains('is-complete');cell.classList.toggle('is-complete',active);cell.setAttribute('aria-pressed',active?'true':'false');if(active){complete++;days[cell.getAttribute('data-day')||'0']=true;}});if(progress){progress.textContent=Math.round((complete/Math.max(1,cells.length))*100)+'% complete';}if(streak){streak.textContent=Object.keys(days).length+' day streak';}}cells.forEach(function(cell){cell.addEventListener('click',function(){var active=cell.getAttribute('aria-pressed')==='true';cell.setAttribute('aria-pressed',active?'false':'true');cell.classList.toggle('is-complete',!active);update();});});if(reset){reset.addEventListener('click',function(){cells.forEach(function(cell){cell.setAttribute('aria-pressed','false');cell.classList.remove('is-complete');});update();});}update();});
JS;
	}

	private function frontend_files( $template, $instructions ) {
		$title = isset( $template['title'] ) ? (string) $template['title'] : 'Niwa snippet';
		$slug  = sanitize_html_class( sanitize_title( $title ) );
		$body  = trim( (string) $instructions );
		$style = $this->design_context_config();
		$bg    = isset( $style['background_color'] ) && sanitize_hex_color( $style['background_color'] ) ? $style['background_color'] : '#f8fafc';
		$text  = isset( $style['text_color'] ) && sanitize_hex_color( $style['text_color'] ) ? $style['text_color'] : '#18151f';
		$accent = isset( $style['accent_color'] ) && sanitize_hex_color( $style['accent_color'] ) ? $style['accent_color'] : '#9b6bd3';
		$button = isset( $style['button_background'] ) && sanitize_hex_color( $style['button_background'] ) ? $style['button_background'] : '#ffffff';
		$button_text = isset( $style['button_text_color'] ) && sanitize_hex_color( $style['button_text_color'] ) ? $style['button_text_color'] : '#4d2d78';
		if ( '' === $body ) {
			return array(
				array(
					'name'    => 'template.html',
					'content' => '<div class="niwa-template-unresolved" data-niwa-template-unresolved="1"></div>',
				),
				array(
					'name'    => 'style.css',
					'content' => '.niwa-template-unresolved{display:none!important}',
				),
				array(
					'name'    => 'script.js',
					'content' => '',
				),
			);
		}

		return array(
			array(
				'name'    => 'template.html',
				'content' => '<section class="niwa-snippet-' . esc_attr( $slug ) . '">' . "\n"
					. '  <div class="niwa-snippet__inner">' . "\n"
					. '    <h2>' . esc_html( $title ) . '</h2>' . "\n"
					. '    <p>' . esc_html( $body ) . '</p>' . "\n"
					. '    <button type="button" class="niwa-snippet__button">Learn more</button>' . "\n"
					. '  </div>' . "\n"
					. '</section>',
			),
			array(
				'name'    => 'style.css',
				'content' => ".niwa-snippet-{$slug}{padding:clamp(28px,5vw,64px);background:{$bg};color:{$text};border-radius:8px}.niwa-snippet-{$slug} .niwa-snippet__inner{max-width:920px;margin:0 auto}.niwa-snippet-{$slug} h2{margin:0 0 10px;color:inherit;font-size:clamp(28px,4vw,48px);line-height:1.08}.niwa-snippet-{$slug} p{max-width:680px;color:inherit;opacity:.78;font-size:17px;line-height:1.6}.niwa-snippet-{$slug} .niwa-snippet__button{border:1px solid {$accent};background:{$button};color:{$button_text};border-radius:6px;padding:10px 14px;cursor:pointer;font-weight:700}",
			),
			array(
				'name'    => 'script.js',
				'content' => "document.querySelectorAll('.niwa-snippet-{$slug} .niwa-snippet__button').forEach(function(btn){btn.addEventListener('click',function(){btn.dispatchEvent(new CustomEvent('niwaSnippetAction',{bubbles:true}));});});",
			),
		);
	}

	private function admin_files( $template, $instructions ) {
		$title = isset( $template['title'] ) ? sanitize_text_field( (string) $template['title'] ) : 'Niwa Admin Snippet';
		$key   = sanitize_key( isset( $template['slug'] ) ? (string) $template['slug'] : $title );
		$note  = trim( (string) $instructions );
		if ( '' === $note ) {
			$note = isset( $template['prompt'] ) ? (string) $template['prompt'] : '';
		}

		switch ( $this->admin_template_kind( $template, $key ) ) {
			case 'publishing_activity_widget':
				$php = $this->publishing_activity_widget_php( $key, $title, $note );
				break;
			case 'custom_post_type':
				$php = $this->custom_post_type_php( $key, $title, $note );
				break;
			case 'admin_dashboard_widget':
				$php = $this->admin_dashboard_widget_php( $key, $title, $note );
				break;
			case 'admin_column_enhancer':
				$php = $this->admin_column_enhancer_php( $key, $title, $note );
				break;
			default:
				$php = $this->generic_admin_widget_php( $key, $title, $note );
				break;
		}

		return array(
			array(
				'name'    => 'main.php',
				'content' => $php,
			),
			array(
				'name'    => 'style.css',
				'content' => '/* Admin snippet fallbacks enqueue their wp-admin CSS from main.php. */',
			),
		);
	}

	private function admin_template_kind( $template, $key ) {
		$candidates = array( $key );
		if ( isset( $template['elementor_schema']['kind'] ) ) {
			$candidates[] = sanitize_key( (string) $template['elementor_schema']['kind'] );
		}

		foreach ( $candidates as $candidate ) {
			$candidate = str_replace( '-', '_', (string) $candidate );
			if ( in_array( $candidate, array( 'publishing_activity_widget' ), true ) ) {
				return 'publishing_activity_widget';
			}
			if ( in_array( $candidate, array( 'custom_post_type', 'custom_post_type_preview' ), true ) ) {
				return 'custom_post_type';
			}
			if ( in_array( $candidate, array( 'admin_dashboard_widget', 'admin_dashboard_preview' ), true ) ) {
				return 'admin_dashboard_widget';
			}
			if ( in_array( $candidate, array( 'admin_column_enhancer', 'admin_column_preview' ), true ) ) {
				return 'admin_column_enhancer';
			}
		}

		return 'generic';
	}

	private function admin_widget_id( $key ) {
		return 'niwa_snippet_' . sanitize_key( $key );
	}

	private function php_literal( $value ) {
		return var_export( (string) $value, true );
	}

	private function replace_admin_placeholders( $php, $values ) {
		foreach ( $values as $key => $value ) {
			$php = str_replace( '__' . strtoupper( $key ) . '__', $this->php_literal( $value ), $php );
		}
		return $php;
	}

	private function publishing_activity_widget_php( $key, $title, $note ) {
		$php = <<<'PHP'
<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

$niwa_widget_id = __WIDGET_ID__;
$niwa_title     = __TITLE__;
$niwa_note      = __NOTE__;

add_action(
	'wp_dashboard_setup',
	function () use ( $niwa_widget_id, $niwa_title, $niwa_note ) {
		if ( ! current_user_can( 'edit_posts' ) ) {
			return;
		}

		wp_add_dashboard_widget(
			$niwa_widget_id,
			$niwa_title,
			function () use ( $niwa_widget_id, $niwa_note ) {
				global $wpdb;

				$post_types = get_post_types( array( 'public' => true ), 'objects' );
				unset( $post_types['attachment'] );
				if ( empty( $post_types ) ) {
					echo '<p>' . esc_html__( 'No public post types found.', 'niwa-ai' ) . '</p>';
					return;
				}

				$selected = isset( $_GET['niwa_publish_type'] ) ? sanitize_key( wp_unslash( $_GET['niwa_publish_type'] ) ) : 'any';
				if ( 'any' !== $selected && ! isset( $post_types[ $selected ] ) ) {
					$selected = 'any';
				}

				$days      = array();
				$today     = current_time( 'timestamp' );
				$start_ts  = $today - ( DAY_IN_SECONDS * 29 );
				$start_sql = wp_date( 'Y-m-d 00:00:00', $start_ts );
				for ( $i = 0; $i < 30; $i++ ) {
					$day          = wp_date( 'Y-m-d', $start_ts + ( DAY_IN_SECONDS * $i ) );
					$days[ $day ] = 0;
				}

				$query_types  = 'any' === $selected ? array_keys( $post_types ) : array( $selected );
				$placeholders = implode( ',', array_fill( 0, count( $query_types ), '%s' ) );
				$sql          = "SELECT DATE(post_date) AS publish_day, COUNT(*) AS total FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_date >= %s AND post_type IN ({$placeholders}) GROUP BY DATE(post_date)";
				$rows         = $wpdb->get_results( $wpdb->prepare( $sql, array_merge( array( $start_sql ), $query_types ) ) );
				foreach ( $rows as $row ) {
					$day = (string) $row->publish_day;
					if ( isset( $days[ $day ] ) ) {
						$days[ $day ] = intval( $row->total );
					}
				}

				$max = max( 1, max( $days ) );
				echo '<div class="niwa-admin-snippet niwa-publishing-activity">';
				if ( '' !== trim( $niwa_note ) ) {
					echo '<p class="niwa-admin-snippet-note">' . esc_html( $niwa_note ) . '</p>';
				}
				echo '<form method="get" class="niwa-admin-snippet-filter"><label for="' . esc_attr( $niwa_widget_id ) . '-type">' . esc_html__( 'Post type', 'niwa-ai' ) . '</label> ';
				echo '<select id="' . esc_attr( $niwa_widget_id ) . '-type" name="niwa_publish_type">';
				echo '<option value="any">' . esc_html__( 'All public types', 'niwa-ai' ) . '</option>';
				foreach ( $post_types as $type => $object ) {
					echo '<option value="' . esc_attr( $type ) . '"' . selected( $selected, $type, false ) . '>' . esc_html( $object->labels->name ) . '</option>';
				}
				echo '</select> <button class="button">' . esc_html__( 'Filter', 'niwa-ai' ) . '</button></form>';
				echo '<div class="niwa-publishing-activity-grid" aria-label="' . esc_attr__( 'Publishing activity for the last 30 days', 'niwa-ai' ) . '">';
				foreach ( $days as $day => $count ) {
					$level = 0 === $count ? 0 : max( 1, min( 4, (int) ceil( ( $count / $max ) * 4 ) ) );
					echo '<span class="niwa-publishing-activity-cell level-' . esc_attr( (string) $level ) . '" title="' . esc_attr( sprintf( '%s: %d', $day, $count ) ) . '"><span class="screen-reader-text">' . esc_html( sprintf( '%s: %d', $day, $count ) ) . '</span></span>';
				}
				echo '</div></div>';
			}
		);
	}
);

add_action(
	'admin_head-index.php',
	function () {
		echo '<style>.niwa-admin-snippet-note{margin:0 0 10px;color:#50575e}.niwa-admin-snippet-filter{display:flex;gap:8px;align-items:center;margin:0 0 12px}.niwa-publishing-activity-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:5px}.niwa-publishing-activity-cell{display:block;aspect-ratio:1;border-radius:3px;background:#f0f0f1}.niwa-publishing-activity-cell.level-1{background:#eadcff}.niwa-publishing-activity-cell.level-2{background:#d4b7ff}.niwa-publishing-activity-cell.level-3{background:#aa75f0}.niwa-publishing-activity-cell.level-4{background:#7f3cc9}</style>';
	}
);
PHP;
		return $this->replace_admin_placeholders(
			$php,
			array(
				'widget_id' => $this->admin_widget_id( $key ),
				'title'     => $title,
				'note'      => $note,
			)
		);
	}

	private function custom_post_type_php( $key, $title, $note ) {
		$php = <<<'PHP'
<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

$niwa_post_type = __POST_TYPE__;
$niwa_title     = __TITLE__;
$niwa_note      = __NOTE__;

add_action(
	'init',
	function () use ( $niwa_post_type ) {
		$labels = array(
			'name'          => __( 'Resources', 'niwa-ai' ),
			'singular_name' => __( 'Resource', 'niwa-ai' ),
			'add_new_item'  => __( 'Add New Resource', 'niwa-ai' ),
			'edit_item'     => __( 'Edit Resource', 'niwa-ai' ),
			'view_item'     => __( 'View Resource', 'niwa-ai' ),
			'search_items'  => __( 'Search Resources', 'niwa-ai' ),
		);

		register_post_type(
			$niwa_post_type,
			array(
				'labels'              => $labels,
				'public'              => false,
				'show_ui'             => true,
				'show_in_menu'        => true,
				'show_in_rest'        => true,
				'menu_icon'           => 'dashicons-portfolio',
				'supports'            => array( 'title', 'editor', 'excerpt', 'thumbnail', 'revisions' ),
				'capability_type'     => 'post',
				'map_meta_cap'        => true,
				'hierarchical'        => false,
				'has_archive'         => false,
				'publicly_queryable'  => false,
				'exclude_from_search' => true,
				'rewrite'             => false,
			)
		);
	}
);

add_filter(
	'manage_' . $niwa_post_type . '_posts_columns',
	function ( $columns ) {
		$columns['niwa_updated'] = __( 'Last updated', 'niwa-ai' );
		return $columns;
	}
);

add_action(
	'manage_' . $niwa_post_type . '_posts_custom_column',
	function ( $column, $post_id ) {
		if ( 'niwa_updated' !== $column ) {
			return;
		}
		echo esc_html( get_the_modified_date( get_option( 'date_format' ), $post_id ) );
	},
	10,
	2
);

add_action(
	'admin_notices',
	function () use ( $niwa_title, $niwa_note ) {
		$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
		if ( ! $screen || 'edit' !== $screen->base || 'niwa_resource' !== $screen->post_type || ! current_user_can( 'edit_posts' ) ) {
			return;
		}
		echo '<div class="notice notice-info"><p><strong>' . esc_html( $niwa_title ) . '</strong>';
		if ( '' !== trim( $niwa_note ) ) {
			echo ' - ' . esc_html( $niwa_note );
		}
		echo '</p></div>';
	}
);
PHP;
		return $this->replace_admin_placeholders(
			$php,
			array(
				'post_type' => 'niwa_resource',
				'title'     => $title,
				'note'      => $note,
			)
		);
	}

	private function admin_dashboard_widget_php( $key, $title, $note ) {
		$php = <<<'PHP'
<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

$niwa_widget_id = __WIDGET_ID__;
$niwa_title     = __TITLE__;
$niwa_note      = __NOTE__;

add_action(
	'wp_dashboard_setup',
	function () use ( $niwa_widget_id, $niwa_title, $niwa_note ) {
		if ( ! current_user_can( 'edit_posts' ) ) {
			return;
		}

		wp_add_dashboard_widget(
			$niwa_widget_id,
			$niwa_title,
			function () use ( $niwa_note ) {
				global $wpdb;

				$posts       = wp_count_posts( 'post' );
				$pages       = wp_count_posts( 'page' );
				$comments    = wp_count_comments();
				$seven_days  = wp_date( 'Y-m-d H:i:s', current_time( 'timestamp' ) - ( DAY_IN_SECONDS * 7 ) );
				$recent_post = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_date >= %s AND post_type IN ('post','page')", $seven_days ) );
				$metrics     = array(
					array( __( 'Published posts', 'niwa-ai' ), isset( $posts->publish ) ? $posts->publish : 0 ),
					array( __( 'Published pages', 'niwa-ai' ), isset( $pages->publish ) ? $pages->publish : 0 ),
					array( __( 'Pending comments', 'niwa-ai' ), isset( $comments->moderated ) ? $comments->moderated : 0 ),
					array( __( 'Published in 7 days', 'niwa-ai' ), $recent_post ),
				);

				echo '<div class="niwa-admin-snippet niwa-kpi-widget">';
				if ( '' !== trim( $niwa_note ) ) {
					echo '<p class="niwa-admin-snippet-note">' . esc_html( $niwa_note ) . '</p>';
				}
				echo '<div class="niwa-kpi-grid">';
				foreach ( $metrics as $metric ) {
					echo '<div class="niwa-kpi-tile"><span class="niwa-kpi-value">' . esc_html( number_format_i18n( (int) $metric[1] ) ) . '</span><span class="niwa-kpi-label">' . esc_html( $metric[0] ) . '</span></div>';
				}
				echo '</div></div>';
			}
		);
	}
);

add_action(
	'admin_head-index.php',
	function () {
		echo '<style>.niwa-admin-snippet-note{margin:0 0 12px;color:#50575e}.niwa-kpi-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.niwa-kpi-tile{padding:12px;border:1px solid #dcdcde;border-radius:6px;background:#fff}.niwa-kpi-value{display:block;font-size:24px;font-weight:700;line-height:1.1;color:#1d2327}.niwa-kpi-label{display:block;margin-top:5px;color:#646970}</style>';
	}
);
PHP;
		return $this->replace_admin_placeholders(
			$php,
			array(
				'widget_id' => $this->admin_widget_id( $key ),
				'title'     => $title,
				'note'      => $note,
			)
		);
	}

	private function admin_column_enhancer_php( $key, $title, $note ) {
		$php = <<<'PHP'
<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

$niwa_post_type = 'post';
$niwa_meta_key  = __META_KEY__;
$niwa_title     = __TITLE__;
$niwa_note      = __NOTE__;

add_filter(
	"manage_{$niwa_post_type}_posts_columns",
	function ( $columns ) {
		$columns['niwa_priority'] = __( 'Priority', 'niwa-ai' );
		return $columns;
	}
);

add_action(
	"manage_{$niwa_post_type}_posts_custom_column",
	function ( $column, $post_id ) use ( $niwa_meta_key ) {
		if ( 'niwa_priority' !== $column ) {
			return;
		}
		$value = get_post_meta( $post_id, $niwa_meta_key, true );
		echo '' === $value ? '&mdash;' : esc_html( (string) $value );
	},
	10,
	2
);

add_filter(
	"manage_edit-{$niwa_post_type}_sortable_columns",
	function ( $columns ) {
		$columns['niwa_priority'] = 'niwa_priority';
		return $columns;
	}
);

add_action(
	'pre_get_posts',
	function ( $query ) use ( $niwa_post_type, $niwa_meta_key ) {
		if ( ! is_admin() || ! $query->is_main_query() || 'niwa_priority' !== $query->get( 'orderby' ) ) {
			return;
		}

		$query_post_type = $query->get( 'post_type' );
		if ( '' === $query_post_type ) {
			$query_post_type = 'post';
		}
		if ( $niwa_post_type !== $query_post_type ) {
			return;
		}

		$query->set( 'meta_key', $niwa_meta_key );
		$query->set( 'orderby', 'meta_value_num' );
	}
);

add_action(
	'add_meta_boxes',
	function () use ( $niwa_post_type, $niwa_meta_key, $niwa_title, $niwa_note ) {
		add_meta_box(
			'niwa_priority_meta',
			$niwa_title,
			function ( $post ) use ( $niwa_meta_key, $niwa_note ) {
				wp_nonce_field( 'niwa_priority_meta_save', 'niwa_priority_meta_nonce' );
				$value = get_post_meta( $post->ID, $niwa_meta_key, true );
				if ( '' !== trim( $niwa_note ) ) {
					echo '<p>' . esc_html( $niwa_note ) . '</p>';
				}
				echo '<p><label for="niwa_priority_value">' . esc_html__( 'Priority number', 'niwa-ai' ) . '</label></p>';
				echo '<input type="number" min="0" step="1" id="niwa_priority_value" name="niwa_priority_value" value="' . esc_attr( (string) $value ) . '" class="widefat" />';
			},
			$niwa_post_type,
			'side'
		);
	}
);

add_action(
	"save_post_{$niwa_post_type}",
	function ( $post_id ) use ( $niwa_meta_key ) {
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}
		if ( ! isset( $_POST['niwa_priority_meta_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['niwa_priority_meta_nonce'] ) ), 'niwa_priority_meta_save' ) ) {
			return;
		}
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}

		$value = isset( $_POST['niwa_priority_value'] ) ? absint( wp_unslash( $_POST['niwa_priority_value'] ) ) : 0;
		if ( $value > 0 ) {
			update_post_meta( $post_id, $niwa_meta_key, $value );
		} else {
			delete_post_meta( $post_id, $niwa_meta_key );
		}
	}
);
PHP;
		return $this->replace_admin_placeholders(
			$php,
			array(
				'meta_key' => '_niwa_priority',
				'title'    => $title,
				'note'     => $note,
			)
		);
	}

	private function generic_admin_widget_php( $key, $title, $note ) {
		$php = <<<'PHP'
<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

$niwa_widget_id = __WIDGET_ID__;
$niwa_title     = __TITLE__;
$niwa_note      = __NOTE__;

add_action(
	'wp_dashboard_setup',
	function () use ( $niwa_widget_id, $niwa_title, $niwa_note ) {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		wp_add_dashboard_widget(
			$niwa_widget_id,
			$niwa_title,
			function () use ( $niwa_note ) {
				echo '<p class="niwa-admin-snippet-note">' . esc_html( $niwa_note ) . '</p>';
			}
		);
	}
);
PHP;
		return $this->replace_admin_placeholders(
			$php,
			array(
				'widget_id' => $this->admin_widget_id( $key ),
				'title'     => $title,
				'note'      => $note,
			)
		);
	}
}
