<?php
/**
 * Dynamic Forms Logic handler.
 *
 * @package Replyan_AI
 */

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

class Replyan_AI_Logic_Forms implements Replyan_AI_Intent_Interface {

	/**
	 * Register hooks.
	 */
	public function register_hooks(): void {
		require_once __DIR__ . '/class-replyan-ai-form-settings.php';
		require_once __DIR__ . '/class-replyan-ai-appointment-validator.php';

		// Standalone Forms
		add_action( 'init', array( $this, 'add_rewrite_rules' ) );
		add_filter( 'query_vars', array( $this, 'add_query_vars' ) );
		add_action( 'template_redirect', array( $this, 'render_standalone_form' ) );

		// Forms CRUD
		add_action( 'wp_ajax_replyan_ai_get_forms', array( $this, 'get_forms' ) );
		add_action( 'wp_ajax_replyan_ai_save_form', array( $this, 'save_form' ) );
		add_action( 'wp_ajax_replyan_ai_delete_form', array( $this, 'delete_form' ) );

		// Form Fields CRUD
		add_action( 'wp_ajax_replyan_ai_get_form_fields', array( $this, 'get_form_fields' ) );
		add_action( 'wp_ajax_replyan_ai_save_form_fields', array( $this, 'save_form_fields' ) );

		// Submissions
		add_action( 'wp_ajax_replyan_ai_get_form_submissions', array( $this, 'get_form_submissions' ) );
		add_action( 'wp_ajax_replyan_ai_export_form_submissions', array( $this, 'export_form_submissions' ) );
		add_action( 'wp_ajax_replyan_ai_edit_form_submission', array( $this, 'edit_form_submission' ) );

		// Session-scoped submissions (Leads tab)
		add_action( 'wp_ajax_replyan_ai_get_session_submission', array( $this, 'get_session_submission' ) );
		add_action( 'wp_ajax_replyan_ai_save_session_submission', array( $this, 'save_session_submission' ) );

		// Agent Forms Mapping
		add_action( 'wp_ajax_replyan_ai_get_agent_forms', array( $this, 'get_agent_forms' ) );
		add_action( 'wp_ajax_replyan_ai_save_agent_forms', array( $this, 'save_agent_forms' ) );

		// Frontend Fetch & Submission
		add_action( 'wp_ajax_replyan_ai_get_dynamic_form', array( $this, 'get_dynamic_form' ) );
		add_action( 'wp_ajax_nopriv_replyan_ai_get_dynamic_form', array( $this, 'get_dynamic_form' ) );
		add_action( 'wp_ajax_replyan_ai_submit_dynamic_form', array( $this, 'submit_dynamic_form' ) );
		add_action( 'wp_ajax_nopriv_replyan_ai_submit_dynamic_form', array( $this, 'submit_dynamic_form' ) );
		add_action( 'wp_ajax_replyan_ai_get_available_slots', array( $this, 'get_available_slots' ) );
		add_action( 'wp_ajax_nopriv_replyan_ai_get_available_slots', array( $this, 'get_available_slots' ) );

		// Register with Intent Engine
		if ( class_exists( 'Replyan_AI_Intent_Engine' ) ) {
			Replyan_AI_Intent_Engine::instance()->register_intent( $this );
		}
	}

	/**
	 * Get the unique action name for this intent.
	 */
	public function get_action_name(): string {
		return 'show_form';
	}

	/**
	 * Handle the parsed intent (optional logic).
	 */
	public function handle( array $payload, string $session_id, array $context = array() ): array {
		return $payload; // Frontend handles the display logic natively.
	}

	/**
	 * Get dynamic forms capability instructions.
	 */
	public function get_instructions( string $session_id, int $agent_id ): string {
		global $wpdb;
		$forms_table       = $wpdb->prefix . 'replyan_forms';
		$agent_forms_table = $wpdb->prefix . 'replyan_agent_forms';

		// If no agent_id provided, try to find the active or default agent
		if ( ! $agent_id ) {
			$settings = Replyan_AI_Settings::get();
			$agent_id = ! empty( $settings['default_agent_id'] ) ? (int) $settings['default_agent_id'] : 0;
			if ( ! $agent_id ) {
				$agents_table = $wpdb->prefix . 'replyan_ai_agents';
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
				$latest_agent = $wpdb->get_row( "SELECT id FROM {$agents_table} ORDER BY created_at DESC LIMIT 1", ARRAY_A );
				$agent_id     = $latest_agent ? (int) $latest_agent['id'] : 0;
			}
		}

		$forms = array();
		if ( $agent_id ) {
			// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
			$forms = $wpdb->get_results( $wpdb->prepare( "
				SELECT f.id, f.name, f.slug, f.ai_instruction, f.description 
				FROM {$forms_table} f
				INNER JOIN {$agent_forms_table} af ON f.id = af.form_id
				WHERE af.agent_id = %d AND f.status = 'active'
			", $agent_id ) );
			// phpcs:enable
		}

		// Fallback: If no forms mapped to specific agent, get all active forms
		if ( empty( $forms ) ) {
			// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
			$forms = $wpdb->get_results( "
				SELECT id, name, slug, ai_instruction, description 
				FROM {$forms_table} 
				WHERE status = 'active'
			" );
			// phpcs:enable
		}

		if ( empty( $forms ) ) {
			return '';
		}

		$form_instructions  = "\"show_form\": Use this action whenever the user expresses ANY intent or desire to book, schedule, make an appointment, fill out a form, inquire, register, or submit information matching an available form.\n";
		$form_instructions .= "CRITICAL RULES FOR FORMS:\n";
		$form_instructions .= "- When a user wants to make an appointment, schedule a viewing, or book a visit (e.g. 'i want to make appointment tommorow', 'can i schedule an appointment', 'book a viewing', 'appointment please'), you MUST IMMEDIATELY trigger the \"show_form\" action.\n";
		$form_instructions .= "- Do NOT ask the user for their name, phone number, email, date, or time in conversation text. The interactive form is designed to collect these details directly!\n";
		$form_instructions .= "- In the JSON \"reply\" field, provide a friendly and helpful invitation to open and fill out the form.\n";
		$form_instructions .= "You MUST output EXACTLY this JSON structure:\n";
		$form_instructions .= '{"reply": "Polite invitation message...", "action": "show_form", "form_id": "slug-of-the-form"}' . "\n\n";
		$form_instructions .= "Available Forms to trigger:\n";

		foreach ( $forms as $form ) {
			$form_instructions .= "- Name: {$form->name}\n";
			$form_instructions .= "  Slug (form_id): {$form->slug}\n";
			$form_instructions .= "  When to trigger this form: {$form->ai_instruction}\n";
			$form_instructions .= "  Internal Description: " . ( $form->description ?: 'Please fill out this form.' ) . "\n";
			
			if ( class_exists( 'Replyan_AI_Form_Settings' ) ) {
				$settings = Replyan_AI_Form_Settings::get_settings( $form->id );
				if ( ! empty( $settings['is_appointment_settings'] ) ) {
					$form_instructions .= "  BUSINESS RULES (You MUST enforce these before offering an appointment):\n";
					if ( ! empty( $settings['time_range'] ) && is_array( $settings['time_range'] ) ) {
						$form_instructions .= "    - Business Hours: {$settings['time_range'][0]} to {$settings['time_range'][1]}\n";
					}
					if ( ! empty( $settings['time_interval'] ) ) {
						$form_instructions .= "    - Time slots are only available every {$settings['time_interval']} minutes.\n";
					}
					if ( ! empty( $settings['max_appointments_per_day'] ) ) {
						$form_instructions .= "    - Max total appointments per day: {$settings['max_appointments_per_day']}\n";
					}
					if ( ! empty( $settings['max_appointments_per_slot'] ) ) {
						$form_instructions .= "    - Max appointments per exact time slot: {$settings['max_appointments_per_slot']}\n";
					}
					if ( ! empty( $settings['max_appointments_per_customer'] ) ) {
						$form_instructions .= "    - Max appointments per customer per day: {$settings['max_appointments_per_customer']}\n";
					}
					if ( ! empty( $settings['overlap_time_period'] ) ) {
						$unit = ! empty( $settings['overlap_time_unit'] ) ? $settings['overlap_time_unit'] : 'minutes';
						$form_instructions .= "    - Buffer/overlap period: There MUST be at least a {$settings['overlap_time_period']} {$unit} gap between appointments.\n";
					}
				}
			}
			$form_instructions .= "\n";
		}

		return trim( $form_instructions );
	}

	/**
	 * Verify nonce and admin capability.
	 */
	private function verify_admin_ajax(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing
		$nonce = isset( $_REQUEST['nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ) : '';
		if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'replyan_ai_admin_settings' ) ) {
			wp_send_json_error( array( 'message' => 'Invalid nonce.' ), 403 );
		}
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
		}
	}

	/**
	 * Get forms list.
	 */
	public function get_forms(): void {
		$this->verify_admin_ajax();

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_forms';

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$page     = isset( $_POST['page'] ) ? max( 1, intval( $_POST['page'] ) ) : 1;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$per_page = isset( $_POST['per_page'] ) ? max( 1, intval( $_POST['per_page'] ) ) : 20;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$search   = isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '';

		$offset = ( $page - 1 ) * $per_page;
		$where  = 'WHERE 1=1';
		$args   = array();

		if ( ! empty( $search ) ) {
			$where .= ' AND (name LIKE %s OR slug LIKE %s)';
			$search_like = '%' . $wpdb->esc_like( $search ) . '%';
			$args[]      = $search_like;
			$args[]      = $search_like;
		}

		$query       = "SELECT * FROM {$table} {$where} ORDER BY created_at DESC LIMIT %d OFFSET %d";
		$count_query = "SELECT COUNT(*) FROM {$table} {$where}";

		$args[] = $per_page;
		$args[] = $offset;

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$total = $wpdb->get_var( $args ? $wpdb->prepare( $count_query, array_slice( $args, 0, -2 ) ) : $count_query );
		$forms = $wpdb->get_results( $wpdb->prepare( $query, $args ), ARRAY_A );
		// phpcs:enable

		// Append settings to each form
		if ( ! empty( $forms ) && class_exists( 'Replyan_AI_Form_Settings' ) ) {
			foreach ( $forms as &$form ) {
				$form['settings'] = Replyan_AI_Form_Settings::get_settings( (int) $form['id'] );
			}
		}

		wp_send_json_success( array(
			'forms' => $forms,
			'total' => (int) $total,
			'page'  => $page,
		) );
	}

	/**
	 * Save form.
	 */
	public function save_form(): void {
		$this->verify_admin_ajax();

		// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$data = isset( $_POST['data'] ) ? json_decode( wp_unslash( $_POST['data'] ), true ) : array();
		if ( empty( $data['name'] ) || empty( $data['slug'] ) ) {
			wp_send_json_error( array( 'message' => 'Name and slug are required.' ) );
		}

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_forms';

		$form_id         = ! empty( $data['id'] ) ? intval( $data['id'] ) : 0;
		$name            = sanitize_text_field( $data['name'] );
		$slug            = sanitize_title( $data['slug'] );
		$description     = sanitize_textarea_field( $data['description'] ?? '' );
		$ai_instruction  = sanitize_textarea_field( $data['ai_instruction'] ?? '' );
		$button_text     = sanitize_text_field( $data['button_text'] ?? '' );
		$success_message = sanitize_textarea_field( $data['success_message'] ?? '' );
		$status          = sanitize_text_field( $data['status'] ?? 'active' );

		// Check if slug exists
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$existing = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$table} WHERE slug = %s AND id != %d", $slug, $form_id ) );
		if ( $existing ) {
			wp_send_json_error( array( 'message' => 'A form with this slug already exists.' ) );
		}

		$form_data = array(
			'name'            => $name,
			'slug'            => $slug,
			'description'     => $description,
			'ai_instruction'  => $ai_instruction,
			'button_text'     => $button_text,
			'success_message' => $success_message,
			'status'          => $status,
			'updated_at'      => current_time( 'mysql' ),
		);

		if ( $form_id ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->update( $table, $form_data, array( 'id' => $form_id ) );
			$saved_id = $form_id;
		} else {
			$form_data['created_at'] = current_time( 'mysql' );
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->insert( $table, $form_data );
			$saved_id = $wpdb->insert_id;
		}

		if ( isset( $data['settings'] ) && is_array( $data['settings'] ) ) {
			if ( class_exists( 'Replyan_AI_Form_Settings' ) ) {
				Replyan_AI_Form_Settings::save_settings( $saved_id, $data['settings'] );
			}
		}

		wp_send_json_success( array( 'id' => $saved_id ) );
	}

	/**
	 * Delete form.
	 */
	public function delete_form(): void {
		$this->verify_admin_ajax();
		
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$form_id = isset( $_POST['id'] ) ? intval( $_POST['id'] ) : 0;
		if ( ! $form_id ) {
			wp_send_json_error( array( 'message' => 'Invalid ID.' ) );
		}

		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->delete( $wpdb->prefix . 'replyan_forms', array( 'id' => $form_id ) );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->delete( $wpdb->prefix . 'replyan_form_fields', array( 'form_id' => $form_id ) );
		
		wp_send_json_success();
	}

	/**
	 * Get form fields.
	 */
	public function get_form_fields(): void {
		$this->verify_admin_ajax();

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$form_id = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_form_fields';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE form_id = %d ORDER BY sort_order ASC", $form_id ), ARRAY_A );

		// Decode options back to array for frontend
		if ( $fields ) {
			foreach ( $fields as &$field ) {
				if ( ! empty( $field['options'] ) ) {
					$field['options'] = json_decode( $field['options'], true );
				}
			}
		}

		wp_send_json_success( array( 'fields' => $fields ) );
	}

	/**
	 * Save form fields.
	 */
	public function save_form_fields(): void {
		$this->verify_admin_ajax();

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$form_id = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$fields  = isset( $_POST['fields'] ) ? json_decode( wp_unslash( $_POST['fields'] ), true ) : array();

		if ( ! $form_id ) {
			wp_send_json_error( array( 'message' => 'Form ID required.' ) );
		}

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_form_fields';

		// Overwrite all fields for simplicity of sync
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->delete( $table, array( 'form_id' => $form_id ) );

		if ( ! empty( $fields ) && is_array( $fields ) ) {
			$sort_order = 0;
			foreach ( $fields as $field ) {
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$wpdb->insert( $table, array(
					'form_id'     => $form_id,
					'label'       => sanitize_text_field( $field['label'] ?? '' ),
					'field_key'   => sanitize_title( $field['field_key'] ?? '' ),
					'type'        => sanitize_text_field( $field['type'] ?? 'text' ),
					'placeholder' => sanitize_text_field( $field['placeholder'] ?? '' ),
					'help_text'   => sanitize_textarea_field( $field['help_text'] ?? '' ),
					'options'     => isset( $field['options'] ) ? wp_json_encode( $field['options'] ) : null,
					'is_required' => ! empty( $field['is_required'] ) ? 1 : 0,
					'sort_order'  => $sort_order++,
					'updated_at'  => current_time( 'mysql' ),
					'created_at'  => current_time( 'mysql' ),
				) );
			}
		}

		wp_send_json_success();
	}

	/**
	 * Get form submissions.
	 */
	public function get_form_submissions(): void {
		$this->verify_admin_ajax();

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_form_submissions';

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$page     = isset( $_POST['page'] ) ? max( 1, intval( $_POST['page'] ) ) : 1;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$per_page = isset( $_POST['per_page'] ) ? max( 1, intval( $_POST['per_page'] ) ) : 20;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$form_id  = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$search      = isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$date_filter = isset( $_POST['date_filter'] ) ? sanitize_text_field( wp_unslash( $_POST['date_filter'] ) ) : '';

		$offset = ( $page - 1 ) * $per_page;
		$where  = 'WHERE 1=1';
		$args   = array();

		if ( $form_id ) {
			$where .= ' AND form_id = %d';
			$args[] = $form_id;
		}

		if ( $search ) {
			$where .= ' AND `values` LIKE %s';
			$args[] = '%' . $wpdb->esc_like( $search ) . '%';
		}

		if ( $date_filter ) {
			if ( class_exists( 'Replyan_AI_Form_Settings' ) ) {
				$settings = Replyan_AI_Form_Settings::get_settings( $form_id );
				if ( isset( $settings['is_appointment_settings'] ) && ! empty( $settings['is_appointment_settings'] ) && $settings['is_appointment_settings'] ) {
					// Search inside the JSON values for the appointment date
					$where .= ' AND `values` LIKE %s';
					$args[] = '%' . $wpdb->esc_like( $date_filter ) . '%';
				} else {
					// Search by creation date
					$where .= ' AND DATE(created_at) = %s';
					$args[] = $date_filter;
				}
			} else {
				$where .= ' AND DATE(created_at) = %s';
				$args[] = $date_filter;
			}
		}

		$query       = "SELECT * FROM {$table} {$where} ORDER BY created_at DESC LIMIT %d OFFSET %d";
		$count_query = "SELECT COUNT(*) FROM {$table} {$where}";

		$args[] = $per_page;
		$args[] = $offset;

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$total       = $wpdb->get_var( $args ? $wpdb->prepare( $count_query, array_slice( $args, 0, -2 ) ) : $count_query );
		$submissions = $wpdb->get_results( $wpdb->prepare( $query, $args ), ARRAY_A );
		// phpcs:enable

		if ( $submissions ) {
			foreach ( $submissions as &$sub ) {
				$sub['values'] = json_decode( $sub['values'], true );
			}
		}

		$fields_table = $wpdb->prefix . 'replyan_form_fields';
		$fields       = array();
		if ( $form_id ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
			$fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$fields_table} WHERE form_id = %d ORDER BY sort_order ASC", $form_id ), ARRAY_A );
		}

		wp_send_json_success( array(
			'submissions' => $submissions,
			'total'       => (int) $total,
			'page'        => $page,
			'fields'      => $fields,
		) );
		wp_die();
	}

	/**
	 * Edit a form submission.
	 */
	public function edit_form_submission(): void {
		$this->verify_admin_ajax();

		$submission_id = isset( $_POST['submission_id'] ) ? intval( $_POST['submission_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Missing
		$values_json   = isset( $_POST['values'] ) ? wp_unslash( $_POST['values'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing

		if ( ! $submission_id || empty( $values_json ) ) {
			wp_send_json_error( array( 'message' => __( 'Missing required parameters.', 'replyan-ai' ) ) );
		}

		$decoded_values = json_decode( $values_json, true );
		if ( ! is_array( $decoded_values ) ) {
			wp_send_json_error( array( 'message' => __( 'Invalid values payload.', 'replyan-ai' ) ) );
		}

		global $wpdb;
		$table_name = $wpdb->prefix . 'replyan_form_submissions';

		// Fetch existing submission
		$existing = $wpdb->get_row( $wpdb->prepare( "SELECT `values` FROM {$table_name} WHERE id = %d", $submission_id ), ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		if ( ! $existing ) {
			wp_send_json_error( array( 'message' => __( 'Submission not found.', 'replyan-ai' ) ) );
		}

		$current_values = json_decode( $existing['values'], true );
		if ( ! is_array( $current_values ) ) {
			$current_values = array();
		}

		// Merge new values
		foreach ( $decoded_values as $k => $v ) {
			$current_values[ sanitize_text_field( $k ) ] = sanitize_textarea_field( $v );
		}

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$updated = $wpdb->update(
			$table_name,
			array(
				'values'     => wp_json_encode( $current_values ),
				'updated_at' => current_time( 'mysql' ),
			),
			array( 'id' => $submission_id ),
			array( '%s', '%s' ),
			array( '%d' )
		);

		if ( false === $updated ) {
			wp_send_json_error( array( 'message' => __( 'Failed to update submission.', 'replyan-ai' ) ) );
		}

		wp_send_json_success( array( 'message' => __( 'Submission updated successfully.', 'replyan-ai' ) ) );
	}

	/**
	 * Export form submissions. as CSV.
	 */
	public function export_form_submissions(): void {
		$this->verify_admin_ajax();

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$form_id = isset( $_GET['form_id'] ) ? intval( $_GET['form_id'] ) : 0;
		if ( ! $form_id ) {
			wp_die( 'Invalid form' );
		}

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_form_submissions';
		
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$submissions = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE form_id = %d ORDER BY created_at DESC", $form_id ), ARRAY_A );
		
		$fields_table = $wpdb->prefix . 'replyan_form_fields';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$fields_table} WHERE form_id = %d ORDER BY sort_order ASC", $form_id ), ARRAY_A );
		
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="submissions-' . $form_id . '-' . gmdate( 'Y-m-d' ) . '.csv"' );

		$output = fopen( 'php://output', 'w' );
		
		if ( $submissions ) {
			$headers = array();
			
			// Add ordered fields first
			if ( $fields ) {
				foreach ( $fields as $field ) {
					$headers[$field['field_key']] = $field['label'];
				}
			}

			// Add any extra dynamic fields
			foreach ( $submissions as $sub ) {
				$values = json_decode( $sub['values'], true );
				if ( is_array( $values ) ) {
					foreach ( array_keys( $values ) as $k ) {
						if ( ! isset( $headers[$k] ) ) {
							$headers[$k] = ucwords( str_replace( '_', ' ', $k ) );
						}
					}
				}
			}

			$csv_headers = array_merge( array_values( $headers ), array( 'Date' ) );
			
			fputcsv( $output, $csv_headers );
			
			$header_keys = array_keys( $headers );
			foreach ( $submissions as $sub ) {
				$row = array();
				$values = json_decode( $sub['values'], true );
				foreach ( $header_keys as $hk ) {
					$row[] = isset( $values[$hk] ) ? (string) $values[$hk] : '';
				}
				$row[] = $sub['created_at'];
				fputcsv( $output, $row );
			}
		} else {
			fputcsv( $output, array( 'No submissions found' ) );
		}
		
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
		fclose( $output );
		exit;
	}

	/**
	 * Submit form from frontend.
	 */
	/**
	 * Get a dynamic form for the frontend by its slug
	 */
	public function get_dynamic_form(): void {
		// Nonce check can be skipped for public fetching, or we can use the general chat nonce
		// Let's use the chat nonce for security if possible, though a public form might not strict need it.
		// For now, no strict nonce is needed to just view a form template, but we can verify it exists.

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$slug = sanitize_text_field( wp_unslash( $_POST['slug'] ?? '' ) );
		if ( ! $slug ) {
			wp_send_json_error( array( 'message' => 'Slug is required.' ), 400 );
		}

		global $wpdb;
		$forms_table  = $wpdb->prefix . 'replyan_forms';
		$fields_table = $wpdb->prefix . 'replyan_form_fields';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$form = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$forms_table} WHERE slug = %s AND status = 'active'", $slug ), ARRAY_A );

		if ( ! $form ) {
			wp_send_json_error( array( 'message' => 'Form not found or inactive.' ), 404 );
		}

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$fields = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$fields_table} WHERE form_id = %d ORDER BY sort_order ASC", $form['id'] ), ARRAY_A );

		wp_send_json_success( array(
			'form'   => $form,
			'fields' => $fields,
		) );
	}

	public function submit_dynamic_form(): void {
		// Verify frontend nonce
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'replyan_ai_chat' ) ) {
			wp_send_json_error( array( 'message' => 'Session expired. Please refresh the page.' ), 403 );
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$form_id    = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$session_id = isset( $_POST['session_id'] ) ? sanitize_text_field( wp_unslash( $_POST['session_id'] ) ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$values     = isset( $_POST['values'] ) ? wp_unslash( $_POST['values'] ) : '{}';

		if ( ! $form_id ) {
			wp_send_json_error( array( 'message' => 'Invalid form.' ) );
		}
		
		$decoded_values = json_decode( $values, true );
		if ( ! is_array( $decoded_values ) ) {
			$decoded_values = array();
		}

		if ( class_exists( 'Replyan_AI_Form_Settings' ) ) {
			$settings = Replyan_AI_Form_Settings::get_settings( $form_id );
			if ( ! empty( $settings['is_appointment_settings'] ) ) {
				if ( ! class_exists( 'Replyan_AI_Appointment_Validator' ) ) {
					require_once __DIR__ . '/class-replyan-ai-appointment-validator.php';
				}
				$validator = new Replyan_AI_Appointment_Validator( $form_id );
				$validation = $validator->validate_submission( get_current_user_id() ?: 0, $session_id, $decoded_values );
				
				if ( is_wp_error( $validation ) ) {
					wp_send_json_error( array( 'message' => $validation->get_error_message() ) );
				}
			}
		}

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_form_submissions';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->insert( $table, array(
			'form_id'    => $form_id,
			'session_id' => $session_id,
			'user_id'    => get_current_user_id() ?: null,
			'values'     => $values,
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			'ip_address' => isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '',
			'user_agent' => sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ?? '' ) ),
			'created_at' => current_time( 'mysql' ),
			'updated_at' => current_time( 'mysql' ),
		) );

		// Return the configured success message
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$form = $wpdb->get_row( $wpdb->prepare( "SELECT success_message FROM {$wpdb->prefix}replyan_forms WHERE id = %d", $form_id ) );
		$msg  = ! empty( $form->success_message ) ? $form->success_message : 'Form submitted successfully.';

		wp_send_json_success( array( 'message' => $msg ) );
	}

	/**
	 * Get assigned forms for an agent.
	 */
	public function get_agent_forms(): void {
		$this->verify_admin_ajax();

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$agent_id = isset( $_POST['agent_id'] ) ? intval( $_POST['agent_id'] ) : 0;

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_agent_forms';
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$forms = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE agent_id = %d ORDER BY sort_order ASC", $agent_id ), ARRAY_A );

		wp_send_json_success( array( 'forms' => $forms ) );
	}

	/**
	 * Save assigned forms for an agent.
	 */
	public function save_agent_forms(): void {
		$this->verify_admin_ajax();

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$agent_id = isset( $_POST['agent_id'] ) ? intval( $_POST['agent_id'] ) : 0;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$forms    = isset( $_POST['forms'] ) ? json_decode( wp_unslash( $_POST['forms'] ), true ) : array();

		if ( ! $agent_id ) {
			wp_send_json_error( array( 'message' => 'Agent ID required.' ) );
		}

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_agent_forms';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->delete( $table, array( 'agent_id' => $agent_id ) );

		if ( ! empty( $forms ) && is_array( $forms ) ) {
			$sort_order = 0;
			foreach ( $forms as $form ) {
				// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
				$wpdb->insert( $table, array(
					'agent_id'   => $agent_id,
					'form_id'    => intval( $form['form_id'] ?? 0 ),
					'is_default' => ! empty( $form['is_default'] ) ? 1 : 0,
					'sort_order' => $sort_order++,
					'created_at' => current_time( 'mysql' ),
				) );
			}
		}

		wp_send_json_success();
	}

	public function get_available_slots(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$form_id    = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$date       = isset( $_POST['date'] ) ? sanitize_text_field( wp_unslash( $_POST['date'] ) ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$session_id = isset( $_POST['session_id'] ) ? sanitize_text_field( wp_unslash( $_POST['session_id'] ) ) : '';

		if ( ! $form_id || empty( $date ) ) {
			wp_send_json_error( array( 'message' => 'Missing form ID or date.' ) );
		}

		if ( class_exists( 'Replyan_AI_Form_Settings' ) ) {
			$settings = Replyan_AI_Form_Settings::get_settings( $form_id );
			if ( empty( $settings['is_appointment_settings'] ) ) {
				wp_send_json_error( array( 'message' => 'Not an appointment form.' ) );
			}

			if ( ! class_exists( 'Replyan_AI_Appointment_Validator' ) ) {
				require_once __DIR__ . '/class-replyan-ai-appointment-validator.php';
			}
			$validator = new Replyan_AI_Appointment_Validator( $form_id );
			
			$slots = $validator->get_available_slots( get_current_user_id() ?: 0, $session_id, $date );
			
			wp_send_json_success( array(
				'slots' => $slots
			) );
		}

		wp_send_json_error( array( 'message' => 'Appointment settings not found.' ) );
	}

	public function add_rewrite_rules(): void {
		add_rewrite_rule( '^rai/([^/]+)/([^/]+)/?', 'index.php?replyan_ai_form=$matches[1]&replyan_ai_session=$matches[2]', 'top' );
	}

	public function add_query_vars( array $vars ): array {
		$vars[] = 'replyan_ai_form';
		$vars[] = 'replyan_ai_session';
		return $vars;
	}

	/**
	 * Get a form submission for a specific session.
	 */
	public function get_session_submission(): void {
		check_ajax_referer( 'replyan_ai_admin_messages', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$form_id    = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$session_id = isset( $_POST['session_id'] ) ? sanitize_text_field( wp_unslash( $_POST['session_id'] ) ) : '';

		if ( ! $form_id || empty( $session_id ) ) {
			wp_send_json_error( array( 'message' => 'Missing parameters.' ) );
		}

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_form_submissions';

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$row = $wpdb->get_row(
			$wpdb->prepare( "SELECT * FROM {$table} WHERE form_id = %d AND session_id = %s ORDER BY created_at DESC LIMIT 1", $form_id, $session_id ),
			ARRAY_A
		);

		if ( $row ) {
			$row['values'] = json_decode( $row['values'], true );
		}

		wp_send_json_success( array( 'submission' => $row ) );
	}

	/**
	 * Save/update a form submission for a specific session.
	 */
	public function save_session_submission(): void {
		check_ajax_referer( 'replyan_ai_admin_messages', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 );
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$form_id    = isset( $_POST['form_id'] ) ? intval( $_POST['form_id'] ) : 0;
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$session_id = isset( $_POST['session_id'] ) ? sanitize_text_field( wp_unslash( $_POST['session_id'] ) ) : '';
		// phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$values     = isset( $_POST['values'] ) ? wp_unslash( $_POST['values'] ) : '{}';

		if ( ! $form_id || empty( $session_id ) ) {
			wp_send_json_error( array( 'message' => 'Missing parameters.' ) );
		}

		global $wpdb;
		$table = $wpdb->prefix . 'replyan_form_submissions';

		// Check if a submission already exists for this form + session
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$existing = $wpdb->get_var(
			$wpdb->prepare( "SELECT id FROM {$table} WHERE form_id = %d AND session_id = %s ORDER BY created_at DESC LIMIT 1", $form_id, $session_id )
		);

		if ( $existing ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->update(
				$table,
				array(
					'values'     => $values,
					'updated_at' => current_time( 'mysql' ),
				),
				array( 'id' => $existing )
			);
		} else {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->insert( $table, array(
				'form_id'    => $form_id,
				'session_id' => $session_id,
				'user_id'    => get_current_user_id() ?: null,
				'values'     => $values,
				'source'     => 'admin',
				'status'     => 'new',
				'created_at' => current_time( 'mysql' ),
				'updated_at' => current_time( 'mysql' ),
			) );
		}

		wp_send_json_success( array( 'message' => 'Submission saved.' ) );
	}

	public function render_standalone_form(): void {
		$form_slug  = get_query_var( 'replyan_ai_form' );
		$session_id = get_query_var( 'replyan_ai_session' );

		if ( $form_slug ) {
			$settings = Replyan_AI_Settings::get();
			?>
			<!DOCTYPE html>
			<html <?php language_attributes(); ?>>
			<head>
				<meta charset="<?php bloginfo( 'charset' ); ?>">
				<meta name="viewport" content="width=device-width, initial-scale=1">
				<title><?php esc_html_e( 'Form', 'replyan-ai' ); ?></title>
				<?php wp_head(); ?>
				<style>
					body { margin: 0; padding: 0; background-color: #f8fafc; min-height: 100vh; display: flex; align-items: center; justify-content: center; }
					#replyan-ai-standalone-form { width: 100%; max-width: 600px; padding: 20px; }
				</style>
			</head>
			<body>
				<div id="replyan-ai-standalone-form" style="--replyan-ai-primary: <?php echo esc_attr( $settings['primary_color'] ); ?>;" data-form="<?php echo esc_attr( $form_slug ); ?>" data-session="<?php echo esc_attr( $session_id ); ?>"></div>
				<?php wp_footer(); ?>
			</body>
			</html>
			<?php
			exit;
		}
	}
}
