<?php
/**
 * AJAX Handlers
 *
 * @package HNG_Commerce
 * @since 1.0.0
 */

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

// phpcs:disable Squiz.Commenting.InlineComment.InvalidEndChar
// phpcs:disable Squiz.Commenting.FunctionComment.Missing
// phpcs:disable Squiz.Commenting.FunctionComment.MissingParamTag
// phpcs:disable WordPress.PHP.YodaConditions.NotYoda
// phpcs:disable Universal.Operators.DisallowShortTernary.Found
// phpcs:disable Generic.CodeAnalysis.EmptyStatement.DetectedIf
// phpcs:disable PSR2.Methods.MethodDeclaration.Underscore
// phpcs:disable WordPress.PHP.DevelopmentFunctions.error_log_error_log
// phpcs:disable Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
// phpcs:disable Squiz.Commenting.ClassComment.Missing
// phpcs:disable Squiz.Commenting.FunctionComment.ParamCommentFullStop
// phpcs:disable Squiz.Commenting.VariableComment.MissingVar
// phpcs:disable WordPress.DB.DirectDatabaseQuery
// phpcs:disable WordPress.DB.PreparedSQL

class HNG_Ajax {

	/**
	 * Instância única
	 */
	private static $instance = null;

	/**
	 * Obter instância
	 */
	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Construtor
	 */
	private function __construct() {
		// Adicionar ao carrinho
		add_action( 'wp_ajax_hng_add_to_cart', array( $this, 'add_to_cart' ) );
		add_action( 'wp_ajax_nopriv_hng_add_to_cart', array( $this, 'add_to_cart' ) );

		// REST fallback para ambientes com bloqueio no admin-ajax.php (ex: WAF)
		add_action( 'rest_api_init', array( $this, 'register_rest_routes' ) );

		// Remover do carrinho
		add_action( 'wp_ajax_hng_remove_from_cart', array( $this, 'remove_from_cart' ) );
		add_action( 'wp_ajax_nopriv_hng_remove_from_cart', array( $this, 'remove_from_cart' ) );

		// Atualizar quantidade
		add_action( 'wp_ajax_hng_update_cart_quantity', array( $this, 'update_cart_quantity' ) );
		add_action( 'wp_ajax_nopriv_hng_update_cart_quantity', array( $this, 'update_cart_quantity' ) );

		// Aplicar cupom
		add_action( 'wp_ajax_hng_apply_coupon', array( $this, 'apply_coupon' ) );
		add_action( 'wp_ajax_nopriv_hng_apply_coupon', array( $this, 'apply_coupon' ) );

		// Remover cupom
		add_action( 'wp_ajax_hng_remove_coupon', array( $this, 'remove_coupon' ) );
		add_action( 'wp_ajax_nopriv_hng_remove_coupon', array( $this, 'remove_coupon' ) );

		// Calcular frete
		add_action( 'wp_ajax_hng_calculate_shipping', array( $this, 'calculate_shipping' ) );
		add_action( 'wp_ajax_nopriv_hng_calculate_shipping', array( $this, 'calculate_shipping' ) );

		// Atualizar frete do carrinho
		add_action( 'wp_ajax_hng_update_cart_shipping', array( $this, 'update_cart_shipping' ) );
		add_action( 'wp_ajax_nopriv_hng_update_cart_shipping', array( $this, 'update_cart_shipping' ) );

		// Rastreamento: Buscar atualizações
		add_action( 'wp_ajax_hng_check_tracking', array( $this, 'check_tracking' ) );
		add_action( 'wp_ajax_nopriv_hng_check_tracking', array( $this, 'check_tracking' ) );

		// Processar pagamento com cartão
		add_action( 'wp_ajax_hng_process_card_payment', array( $this, 'process_card_payment' ) );
		add_action( 'wp_ajax_nopriv_hng_process_card_payment', array( $this, 'process_card_payment' ) );
		// Toggle gateway enable/disable

		// Configurar gateway

		// Import / Export tools (admin only)
		add_action( 'wp_ajax_hng_upload_csv', array( $this, 'upload_csv' ) );
		add_action( 'wp_ajax_hng_import_external_data', array( $this, 'import_external_data' ) );
		add_action( 'wp_ajax_hng_export_products', array( $this, 'export_products' ) );
		add_action( 'wp_ajax_hng_export_orders', array( $this, 'export_orders' ) );

		// Run SQL Import (System Tool)
		add_action( 'wp_ajax_hng_run_sql_import', array( $this, 'run_sql_import' ) );

		// WP-Cron batch processor for imports
		add_action( 'hng_process_import_batch', array( $this, 'process_import_batch' ), 10, 1 );

		// Quote/Appointment Chat handlers (admin and order owner)
		add_action( 'wp_ajax_hng_save_quote_shipping', array( $this, 'save_quote_shipping' ) );
		add_action( 'wp_ajax_hng_send_quote_to_client', array( $this, 'send_quote_to_client' ) );
		add_action( 'wp_ajax_hng_send_order_chat_message', array( $this, 'send_order_chat_message' ) );
		add_action( 'wp_ajax_hng_upload_order_chat_file', array( $this, 'upload_order_chat_file' ) );
		add_action( 'wp_ajax_hng_get_order_chat_messages', array( $this, 'get_order_chat_messages' ) );
		add_action( 'wp_ajax_hng_mark_order_messages_read', array( $this, 'mark_order_messages_read' ) );

		// Customer quote approval handler
		add_action( 'wp_ajax_hng_approve_quote', array( $this, 'approve_quote' ) );
		add_action( 'wp_ajax_hng_reject_quote', array( $this, 'reject_quote' ) );

		// Admin resend quote notification
		add_action( 'wp_ajax_hng_resend_quote_notification', array( $this, 'resend_quote_notification' ) );
	}

	/**
	 * Get post ID from database order ID
	 *
	 * @param int $db_order_id The order ID from hng_orders table
	 * @return int|false The post ID or false if not found
	 */
	private function get_post_id_from_db_order_id( $db_order_id ) {
		// First try to find by _hng_db_order_id meta
		// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Point lookup with posts_per_page=1 for order mapping fallback.
		$posts = get_posts(
			array(
				'post_type'      => 'hng_order',
				'posts_per_page' => 1,
				'post_status'    => 'any',
				'meta_query'     => array(
					array(
						'key'     => '_hng_db_order_id',
						'value'   => $db_order_id,
						'compare' => '=',
					),
				),
			)
		);
		// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_query

		if ( ! empty( $posts ) ) {
			return $posts[0]->ID;
		}

		// Fallback: try by order_number pattern (ORC-000XXX)
		global $wpdb;
		$orders_table = hng_db_full_table_name( 'hng_orders' );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$order = $wpdb->get_row(
			$wpdb->prepare(
				// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is from hng_db_full_table_name().
				"SELECT order_number FROM {$orders_table} WHERE id = %d",
				$db_order_id
			)
		);

		if ( $order && ! empty( $order->order_number ) ) {
			$post_id_from_number = preg_replace( '/^ORC-0*/', '', $order->order_number );
			if ( $post_id_from_number && is_numeric( $post_id_from_number ) ) {
				$post = get_post( intval( $post_id_from_number ) );
				if ( $post && $post->post_type === 'hng_order' ) {
					return intval( $post_id_from_number );
				}
			}
		}

		return false;
	}

	/**
	 * Executes an uploaded SQL file
	 */
	public function run_sql_import() {
		check_ajax_referer( 'hng-commerce-admin', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

		if ( empty( $_FILES['file'] ) ) {
			wp_send_json_error( array( 'message' => __( 'Arquivo não enviado.', 'hng-commerce' ) ) );
		}

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- File array is validated and constrained to .sql below.
		$file = wp_unslash( $_FILES['file'] );
		$ext  = pathinfo( $file['name'], PATHINFO_EXTENSION );
		if ( strtolower( $ext ) !== 'sql' ) {
			wp_send_json_error( array( 'message' => __( 'Apenas arquivos .sql são permitidos.', 'hng-commerce' ) ) );
		}

		// Use WP_Filesystem for reading uploaded file
		global $wp_filesystem;
		if ( empty( $wp_filesystem ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
			WP_Filesystem();
		}
		$content = $wp_filesystem->get_contents( $file['tmp_name'] );
		if ( ! $content ) {
			wp_send_json_error( array( 'message' => __( 'Erro ao ler arquivo SQL.', 'hng-commerce' ) ) );
		}

		global $wpdb;

		// Split SQL by semicolon, but handle cases where semicolons are inside strings if possible.
		// For simplicity, we assume standard dump format where statements end with ;
		// We can use WPDB's query method for each valid statement.

		// Remove comments
		$content = preg_replace( '/^--.*$/m', '', $content );
		$content = preg_replace( '/^\/\*.*\*\/$/m', '', $content );

		$queries  = explode( ';', $content );
		$executed = 0;
		$errors   = 0;

		foreach ( $queries as $query ) {
			$query = trim( $query );
			if ( empty( $query ) ) {
				continue;
			}

			// Replace prefix placeholder if exists (e.g. wp_) with current db prefix
			// This is optional but good for portability.
			// For now, assume SQL has correct headers or generic creates.

			// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Dynamic SQL import executor intentionally runs admin-provided statements.
			$result = $wpdb->query( $query );
			if ( $result === false ) {
				// Log error but continue
				error_log( 'HNG SQL Import Error: ' . $wpdb->last_error . ' | Query: ' . substr( $query, 0, 100 ) );
				++$errors;
			} else {
				++$executed;
			}
		}

		wp_send_json_success(
			array(
				/* translators: 1: number of successful commands, 2: number of errors */
				'message'  => sprintf( __( 'SQL Executado! Comandos bem-sucedidos: %1$d. Erros: %2$d.', 'hng-commerce' ), $executed, $errors ),
				'executed' => $executed,
				'errors'   => $errors,
			)
		);
	}

	/**
	 * Adicionar ao carrinho
	 */
	public function add_to_cart() {
		// Verify nonce from frontend - accept from either add_to_cart or cart_actions
		$request_nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		$nonce_valid   = wp_verify_nonce( $request_nonce, 'hng_add_to_cart' ) ||
						wp_verify_nonce( $request_nonce, 'hng_cart_actions' );
		if ( ! $nonce_valid ) {
			wp_send_json_error( array( 'message' => __( 'Sessão expirada. Recarregue a página.', 'hng-commerce' ) ), 403 );
		}

		$result = $this->process_add_to_cart_request( wp_unslash( $_POST ) );
		if ( $result['success'] ) {
			wp_send_json_success( $result['data'] );
		}
		wp_send_json_error( $result['data'] );
	}



	/**
	 * REST fallback para add_to_cart
	 */
	public function rest_add_to_cart( $request ) {
		// Verify nonce
		$nonce = $request->get_param( 'nonce' );
		if ( ! $nonce || ! wp_verify_nonce( $nonce, 'hng_add_to_cart' ) ) {
			if ( ! $nonce || ! wp_verify_nonce( $nonce, 'hng_cart_actions' ) ) {
				return new WP_REST_Response( array( 'error' => 'Invalid security token' ), 403 );
			}
		}

		$params = $request->get_json_params();
		if ( empty( $params ) ) {
			$params = $request->get_params();
		}
		$result = $this->process_add_to_cart_request( $params );
		if ( $result['success'] ) {
			return new WP_REST_Response( $result['data'], 200 );
		}
		return new WP_REST_Response( $result['data'], 400 );
	}

	public function register_rest_routes() {
		register_rest_route(
			'hng/v1',
			'/add-to-cart',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'rest_add_to_cart' ),
				'permission_callback' => '__return_true',
			)
		);

		register_rest_route(
			'hng/v1',
			'/calculate-shipping',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'rest_calculate_shipping' ),
				'permission_callback' => '__return_true',
			)
		);
	}

	/**
	 * REST API callback para cálculo de frete (evita bloqueios WAF no admin-ajax)
	 */
	public function rest_calculate_shipping( $request ) {
		// Verify nonce
		$nonce = $request->get_param( 'nonce' );
		if ( ! $nonce || ( ! wp_verify_nonce( $nonce, 'hng_calculate_shipping' ) && ! wp_verify_nonce( $nonce, 'hng_cart_actions' ) ) ) {
			return new WP_REST_Response( array( 'error' => 'Invalid security token' ), 403 );
		}

		$params = $request->get_json_params();
		if ( empty( $params ) ) {
			$params = $request->get_params();
		}

		$postcode = preg_replace( '/\D/', '', (string) ( $params['postcode'] ?? '' ) );
		if ( strlen( $postcode ) !== 8 ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => __( 'CEP inválido. Informe 8 dígitos.', 'hng-commerce' ),
				),
				400
			);
		}

		$manager    = HNG_Shipping_Manager::instance();
		$product_id = absint( $params['product_id'] ?? 0 );
		$quantity   = max( 1, absint( $params['quantity'] ?? 1 ) );

		// Se product_id foi informado, calcular para produto específico
		if ( $product_id > 0 ) {
			$package = $manager->build_package_from_product( $product_id, $quantity, $postcode );
		} else {
			// Senão, calcular para o carrinho atual
			$cart = hng_cart();
			if ( $cart->is_empty() ) {
				return new WP_REST_Response(
					array(
						'success' => false,
						'message' => __( 'Carrinho vazio. Adicione produtos para calcular o frete.', 'hng-commerce' ),
					),
					400
				);
			}
			$package = $manager->build_package_from_cart( $postcode );
		}

		$rates = $manager->calculate_shipping( $package );

		if ( is_wp_error( $rates ) ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => $rates->get_error_message(),
				),
				400
			);
		}

		if ( empty( $rates ) ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => __( 'Nenhuma opção de frete disponível para este CEP.', 'hng-commerce' ),
				),
				200
			);
		}

		$methods = array_map(
			static function ( $rate ) {
				$delivery_label = $rate['delivery_time_label'] ?? '';
				return array(
					'id'                  => $rate['id'] ?? '',
					'method_id'           => $rate['method_id'] ?? '',
					'service'             => $rate['service_name'] ?? $rate['method_title'] ?? '',
					'name'                => $rate['service_name'] ?? $rate['method_title'] ?? '',
					'label'               => $rate['label'] ?? '',
					'cost'                => floatval( $rate['cost'] ?? 0 ),
					'delivery_time'       => $delivery_label,
					'delivery_time_text'  => $delivery_label,
					'delivery_time_label' => $delivery_label,
					'raw_delivery_days'   => $rate['delivery_time'] ?? 0,
				);
			},
			$rates
		);

		return new WP_REST_Response(
			array(
				'success' => true,
				'methods' => $methods,
			),
			200
		);
	}

	private function process_add_to_cart_request( $raw ) {
		// Debug apenas em desenvolvimento
		if ( defined( 'HNG_DEBUG' ) && HNG_DEBUG === true ) {
			error_log( 'HNG Debug: process_add_to_cart_request - ' . wp_json_encode( $raw ) );
		}

		$post = wp_unslash( $raw );

		// Validação de entrada rigorosa - SECURITY FIX
		$product_id = absint( $post['product_id'] ?? 0 );
		$quantity   = absint( $post['quantity'] ?? 1 );

		// Validar range de quantidade
		if ( $quantity < 1 ) {
			return array(
				'success' => false,
				'data'    => array( 'message' => __( 'Quantidade deve ser maior que zero.', 'hng-commerce' ) ),
			);
		}

		if ( $quantity > 1000 ) {
			return array(
				'success' => false,
				'data'    => array( 'message' => __( 'Quantidade máxima por item é 1000.', 'hng-commerce' ) ),
			);
		}

		if ( $product_id < 1 ) {
			return array(
				'success' => false,
				'data'    => array( 'message' => __( 'ID de produto inválido.', 'hng-commerce' ) ),
			);
		}
		$variation_id = absint( $post['variation_id'] ?? 0 );
		$variation    = isset( $post['variation'] ) ? (array) $post['variation'] : array();

		if ( empty( $product_id ) ) {
			return array(
				'success' => false,
				'data'    => array( 'message' => __( 'Produto inválido.', 'hng-commerce' ) ),
			);
		}

		$product = hng_get_product( $product_id );

		if ( ! $product->get_id() ) {
			return array(
				'success' => false,
				'data'    => array( 'message' => __( 'Produto não encontrado.', 'hng-commerce' ) ),
			);
		}

		if ( ! $product->is_purchasable() ) {
			return array(
				'success' => false,
				'data'    => array( 'message' => __( 'Este produto não pode ser comprado.', 'hng-commerce' ) ),
			);
		}

		if ( ! $product->is_in_stock() ) {
			return array(
				'success' => false,
				'data'    => array( 'message' => __( 'Produto fora de estoque.', 'hng-commerce' ) ),
			);
		}

		if ( $product->manages_stock() && $quantity > $product->get_stock_quantity() ) {
			return array(
				'success' => false,
				/* translators: %d: available stock quantity */
				'data'    => array( 'message' => sprintf( esc_html__( 'Quantidade indisponível. Estoque: %d unidades.', 'hng-commerce' ), $product->get_stock_quantity() ) ),
			);
		}

		$custom_fields = array();
		if ( ! empty( $post['hng_cf'] ) && is_array( $post['hng_cf'] ) ) {
			foreach ( $post['hng_cf'] as $slug => $value ) {
				$custom_fields[ $slug ] = sanitize_text_field( $value );
			}
		}

		$cart                       = hng_cart();
		$variation['custom_fields'] = $custom_fields;
		$cart_id                    = $cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );

		if ( $cart_id ) {
			if ( ! isset( $_SESSION ) ) {
				session_start();
			}
			if ( ! isset( $_SESSION['hng_cf_checkout'] ) ) {
				$_SESSION['hng_cf_checkout'] = array();
			}
			$_SESSION['hng_cf_checkout'][ $cart_id ] = $custom_fields;

			return array(
				'success' => true,
				'data'    => array(
					'message'       => __( 'Produto adicionado ao carrinho!', 'hng-commerce' ),
					'cart_count'    => $cart->get_cart_contents_count(),
					'cart_subtotal' => hng_price( $cart->get_subtotal() ),
					'cart_total'    => hng_price( $cart->get_total() ),
					'cart_hash'     => md5( wp_json_encode( $cart->get_cart() ) ),
				),
			);
		}

		return array(
			'success' => false,
			'data'    => array( 'message' => __( 'Erro ao adicionar produto ao carrinho.', 'hng-commerce' ) ),
		);
	}


	/**
	 * Calcular frete usando métodos HTTPS (Correios, Melhor Envio, Jadlog)
	 */
	public function calculate_shipping() {
		$nonce    = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		$nonce_ok = wp_verify_nonce( $nonce, 'hng_calculate_shipping' ) ||
					wp_verify_nonce( $nonce, 'hng_cart_actions' );

		if ( ! $nonce_ok ) {
			wp_send_json_error(
				array(
					'message' => __( 'Erro de segurança. Recarregue a página e tente novamente.', 'hng-commerce' ),
				),
				403
			);
		}

		$postcode_raw = isset( $_POST['postcode'] ) ? sanitize_text_field( wp_unslash( $_POST['postcode'] ) ) : '';
		$postcode     = preg_replace( '/\D/', '', $postcode_raw );
		if ( strlen( $postcode ) !== 8 ) {
			wp_send_json_error(
				array(
					'message' => __( 'CEP inválido. Informe 8 dígitos.', 'hng-commerce' ),
				)
			);
		}

		$cart = hng_cart();
		if ( $cart->is_empty() ) {
			wp_send_json_error(
				array(
					'message' => __( 'Carrinho vazio. Adicione produtos para calcular o frete.', 'hng-commerce' ),
				)
			);
		}

		$manager = HNG_Shipping_Manager::instance();
		$package = $manager->build_package_from_cart( $postcode );
		$rates   = $manager->calculate_shipping( $package );

		if ( is_wp_error( $rates ) ) {
			wp_send_json_error(
				array(
					'message' => $rates->get_error_message(),
				)
			);
		}

		if ( empty( $rates ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Nenhuma opção de frete disponível para este CEP.', 'hng-commerce' ),
				)
			);
		}

		// Persistir cotações para seleção posterior
		$cart->set_available_shipping_rates( $postcode, $rates );

		$methods = array_map(
			static function ( $rate ) {
				$delivery_label = $rate['delivery_time_label'] ?? '';
				return array(
					'id'                  => $rate['id'] ?? '',
					'method_id'           => $rate['method_id'] ?? '',
					'service'             => $rate['service_name'] ?? $rate['method_title'] ?? '',
					'name'                => $rate['service_name'] ?? $rate['method_title'] ?? '',
					'label'               => $rate['label'] ?? '',
					'cost'                => floatval( $rate['cost'] ?? 0 ),
					'delivery_time'       => $delivery_label,
					'delivery_time_text'  => $delivery_label,
					'delivery_time_label' => $delivery_label,
					'raw_delivery_days'   => $rate['delivery_time'] ?? 0,
				);
			},
			$rates
		);

		wp_send_json_success(
			array(
				'methods' => $methods,
			)
		);
	}

	/**
	 * Salvar método de frete escolhido no carrinho
	 */
	public function update_cart_shipping() {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng_update_cart_shipping' ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Erro de segurança. Recarregue a página e tente novamente.', 'hng-commerce' ),
				),
				403
			);
		}

		$selected_id = isset( $_POST['method_id'] ) ? sanitize_text_field( wp_unslash( $_POST['method_id'] ) ) : '';
		if ( empty( $selected_id ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Método de frete inválido.', 'hng-commerce' ),
				)
			);
		}

		$cart       = hng_cart();
		$available  = $cart->get_available_shipping_rates();
		$has_quotes = ! empty( $available['rates'] );

		if ( ! $has_quotes ) {
			wp_send_json_error(
				array(
					'message' => __( 'Recalcule o frete antes de selecionar um método.', 'hng-commerce' ),
				)
			);
		}

		if ( ! $cart->select_shipping_rate( $selected_id ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Método de frete não encontrado. Recalcule o frete.', 'hng-commerce' ),
				)
			);
		}

		// Persist immediately to session
		$cart->save_cart();

		wp_send_json_success(
			array(
				'shipping_total' => hng_price( $cart->get_shipping_total() ),
				'cart_total'     => hng_price( $cart->get_total() ),
				'selected'       => $cart->get_selected_shipping(),
			)
		);
	}

	/**
	 * Remover item do carrinho
	 */
	public function remove_from_cart() {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng_cart_actions' ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Sessão expirada. Recarregue a página.', 'hng-commerce' ),
				),
				403
			);
		}

		$cart_id = isset( $_POST['cart_id'] ) ? sanitize_text_field( wp_unslash( $_POST['cart_id'] ) ) : '';

		if ( empty( $cart_id ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'ID do item inválido.', 'hng-commerce' ),
				)
			);
		}

		$cart   = hng_cart();
		$result = $cart->remove( $cart_id );

		if ( $result ) {
			wp_send_json_success(
				array(
					'message'       => __( 'Produto removido do carrinho.', 'hng-commerce' ),
					'cart_count'    => $cart->get_cart_contents_count(),
					'cart_subtotal' => hng_price( $cart->get_subtotal() ),
					'cart_total'    => hng_price( $cart->get_total() ),
				)
			);
		}

		wp_send_json_error(
			array(
				'message' => __( 'Erro ao remover produto.', 'hng-commerce' ),
			)
		);
	}

	/**
	 * Atualizar quantidade de item no carrinho
	 */
	public function update_cart_quantity() {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng_cart_actions' ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Sessão expirada. Recarregue a página.', 'hng-commerce' ),
				),
				403
			);
		}

		$cart_id  = isset( $_POST['cart_id'] ) ? sanitize_text_field( wp_unslash( $_POST['cart_id'] ) ) : '';
		$quantity = isset( $_POST['quantity'] ) ? absint( wp_unslash( $_POST['quantity'] ) ) : 1;

		if ( empty( $cart_id ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'ID do item inválido.', 'hng-commerce' ),
				)
			);
		}

		// Validação de range para prevenir ataques de quantidade
		if ( $quantity < 1 ) {
			wp_send_json_error(
				array(
					'message' => __( 'Quantidade mínima é 1.', 'hng-commerce' ),
				)
			);
		}

		if ( $quantity > 1000 ) {
			wp_send_json_error(
				array(
					'message' => __( 'Quantidade máxima é 1000 por item.', 'hng-commerce' ),
				)
			);
		}

		$cart   = hng_cart();
		$result = $cart->set_quantity( $cart_id, $quantity );

		if ( $result ) {
			$cart_contents = $cart->get_cart();
			$item_subtotal = 0;

			if ( isset( $cart_contents[ $cart_id ] ) ) {
				$item          = $cart_contents[ $cart_id ];
				$item_subtotal = $item['data']->get_price() * $item['quantity'];
			}

			wp_send_json_success(
				array(
					'message'       => __( 'Quantidade atualizada.', 'hng-commerce' ),
					'item_subtotal' => hng_price( $item_subtotal ),
					'cart_count'    => $cart->get_cart_contents_count(),
					'cart_subtotal' => hng_price( $cart->get_subtotal() ),
					'cart_total'    => hng_price( $cart->get_total() ),
				)
			);
		}

		wp_send_json_error(
			array(
				'message' => __( 'Erro ao atualizar quantidade.', 'hng-commerce' ),
			)
		);
	}

	/**
	 * Upload CSV (Import tools)
	 */
	public function upload_csv() {
		check_ajax_referer( 'hng-commerce-admin', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permissão negada.', 'hng-commerce' ) ) );
		}

        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- File upload validated by wp_handle_upload below
		if ( empty( $_FILES['file'] ) ) {
			wp_send_json_error( array( 'message' => __( 'Arquivo não enviado.', 'hng-commerce' ) ) );
		}

		require_once ABSPATH . 'wp-admin/includes/file.php';
		require_once ABSPATH . 'wp-admin/includes/image.php';
		require_once ABSPATH . 'wp-admin/includes/media.php';

		$overrides = array(
			'test_form' => false,
			'mimes'     => array(
				'csv' => 'text/csv',
				'txt' => 'text/plain',
			),
		);
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- File validated by wp_handle_upload
		$file = wp_handle_upload( $_FILES['file'], $overrides );

		if ( isset( $file['error'] ) ) {
			wp_send_json_error( array( 'message' => $file['error'] ) );
		}

		// Inserir como attachment para facilitar uso posterior
		$file_path  = $file['file'];
		$file_name  = basename( $file_path );
		$filetype   = wp_check_filetype( $file_name, null );
		$attachment = array(
			'post_mime_type' => $filetype['type'] ?? 'text/csv',
			'post_title'     => sanitize_file_name( pathinfo( $file_name, PATHINFO_FILENAME ) ),
			'post_content'   => '',
			'post_status'    => 'inherit',
		);

		$attach_id = wp_insert_attachment( $attachment, $file_path );
		if ( ! is_wp_error( $attach_id ) && $attach_id ) {
			$attach_data = wp_generate_attachment_metadata( $attach_id, $file_path );
			wp_update_attachment_metadata( $attach_id, $attach_data );
			// salvar como último CSV carregado para importação
			update_option( 'hng_last_uploaded_csv', $attach_id );
			wp_send_json_success(
				array(
					'message'       => __( 'Arquivo carregado com sucesso.', 'hng-commerce' ),
					'attachment_id' => $attach_id,
					'url'           => $file['url'],
				)
			);
		}

		// fallback
		wp_send_json_success(
			array(
				'message' => __( 'Arquivo carregado com sucesso (não foi possível registrar attachment).', 'hng-commerce' ),
				'file'    => $file,
			)
		);
	}

	/**
	 * Iniciar importação de dados externos (stub/processo em background)
	 */
	public function import_external_data() {
		check_ajax_referer( 'hng-commerce-admin', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

		$attachment_id = isset( $_POST['attachment_id'] ) ? absint( wp_unslash( $_POST['attachment_id'] ) ) : 0;
		$import_type   = isset( $_POST['import_type'] ) ? sanitize_text_field( wp_unslash( $_POST['import_type'] ) ) : 'products';

		if ( ! $attachment_id ) {
			$attachment_id = get_option( 'hng_last_uploaded_csv' );
		}
		if ( ! $attachment_id ) {
			wp_send_json_error( array( 'message' => __( 'Nenhum arquivo CSV encontrado.', 'hng-commerce' ) ) );
		}

		$file_path = get_attached_file( $attachment_id );
		if ( ! $file_path || ! file_exists( $file_path ) ) {
			wp_send_json_error( array( 'message' => __( 'Arquivo não encontrado no servidor.', 'hng-commerce' ) ) );
		}

		// Parse CSV
		$file = new SplFileObject( $file_path );
		$file->setFlags( SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE );

		$headers = $file->fgetcsv();
		if ( empty( $headers ) ) {
			wp_send_json_error( array( 'message' => __( 'Arquivo CSV vazio ou inválido.', 'hng-commerce' ) ) );
		}

		// Map headers
		$map = array();
		foreach ( $headers as $i => $h ) {
			$k = strtolower( trim( (string) $h ) );
			// Cleanup BOM if present
			if ( strpos( $k, "\xEF\xBB\xBF" ) === 0 ) {
				$k = substr( $k, 3 );
			}
			$k         = preg_replace( '/[^a-z0-9_]/', '_', $k );
			$map[ $i ] = $k;
		}

		$processed = 0;
		$created   = 0;
		$updated   = 0;
		$errors    = 0;

		// Process Loop
		while ( ! $file->eof() && ( $row = $file->fgetcsv() ) !== null ) {
			if ( empty( $row ) || ( count( $row ) === 1 && $row[0] === null ) ) {
				continue;
			}

			$data = array();
			foreach ( $row as $i => $val ) {
				if ( isset( $map[ $i ] ) ) {
					$data[ $map[ $i ] ] = trim( $val );
				}
			}

			if ( $import_type === 'orders' ) {
				$res = $this->_import_single_order( $data );
			} else {
				$res = $this->_import_single_product( $data );
			}

			if ( is_wp_error( $res ) ) {
				++$errors;
			} elseif ( $res === 'updated' ) {
					++$updated;
			} else {
				++$created;
			}
			++$processed;
		}

		wp_send_json_success(
			array(
				'message'  => 'Importação finalizada',
				'imported' => array_fill( 0, $created, 1 ), // Stub for frontend length check
				'updated'  => array_fill( 0, $updated, 1 ),
				'errors'   => array_fill( 0, $errors, 1 ),
			)
		);
	}

	private function _import_single_product( $data ) {
		// Simplified Logic: Title, Price, Stock, SKU
		$sku   = $data['sku'] ?? '';
		$name  = $data['name'] ?? ( $data['product_name'] ?? '' );
		$price = $data['price'] ?? ( $data['regular_price'] ?? '' );

		if ( empty( $name ) && empty( $sku ) ) {
			return new WP_Error( 'invalid', 'Sem nome ou sku' );
		}

		$post_id = 0;
		if ( $sku ) {
			// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value -- Exact SKU lookup for import deduplication.
			$found = get_posts(
				array(
					'post_type'  => 'hng_product',
					'meta_key'   => '_sku',
					'meta_value' => $sku,
					'fields'     => 'ids',
				)
			);
			// phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value
			if ( $found ) {
				$post_id = $found[0];
			}
		}

		$args = array(
			'post_title'  => $name,
			'post_type'   => 'hng_product',
			'post_status' => 'publish',
		);

		// Optional description
		if ( ! empty( $data['description'] ) ) {
			$args['post_content'] = $data['description'];
		}

		$is_update = false;
		if ( $post_id ) {
			$args['ID'] = $post_id;
			wp_update_post( $args );
			$is_update = true;
		} else {
			$post_id = wp_insert_post( $args );
			if ( is_wp_error( $post_id ) ) {
				return $post_id;
			}
		}

		// Meta
		if ( $sku ) {
			update_post_meta( $post_id, '_sku', $sku );
		}
		if ( $price ) {
			$price = str_replace( ',', '.', $price );
			update_post_meta( $post_id, '_price', $price );
			update_post_meta( $post_id, '_regular_price', $price );
		}
		if ( isset( $data['stock'] ) ) {
			update_post_meta( $post_id, '_stock_quantity', (int) $data['stock'] );
			update_post_meta( $post_id, '_manage_stock', 'yes' );
		}
		if ( ! empty( $data['image_url'] ) ) {
			// Image logic stub
		}

		return $is_update ? 'updated' : 'created';
	}

	private function _import_single_order( $data ) {
		global $wpdb;
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Controlled CRUD on internal plugin orders table.
		$table = $wpdb->prefix . 'hng_orders';
		if ( function_exists( 'hng_db_full_table_name' ) ) {
			$table = hng_db_full_table_name( 'hng_orders' );
		}

		// Mapping
		$order_number  = $data['order_number'] ?? ( $data['id'] ?? uniqid() );
		$email         = $data['email'] ?? '';
		$total         = $data['total'] ?? 0;
		$status        = $data['status'] ?? 'pending';
		$created_at    = $data['created_at'] ?? current_time( 'mysql' );
		$customer_name = $data['customer_name'] ?? '';

		if ( empty( $email ) && empty( $total ) ) {
			return new WP_Error( 'invalid', 'Dados insuficientes' );
		}

		// Check exists
		$exists = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $table WHERE order_number = %s", $order_number ) );

		$db_data = array(
			'order_number'       => $order_number,
			'billing_email'      => $email,
			'total'              => $total,
			'status'             => $status,
			'created_at'         => $created_at,
			'billing_first_name' => $customer_name,
		);

		if ( $exists ) {
			$wpdb->update( $table, $db_data, array( 'id' => $exists ) );
			return 'updated';
		} else {
			$wpdb->insert( $table, $db_data );
			return 'created';
		}
	}

	/**
	 * Stub for batch processor if needed by cron (old ref)
	 */
	public function process_import_batch( $attachment_id ) {
		// Placeholder to prevent fatal error if cron fires
	}

	/**
	 * Exportar produtos como CSV (download)
	 */
	public function export_products() {
		// Nonce via GET/REQUEST
		$nonce = isset( $_REQUEST['nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng-commerce-admin' ) ) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_die() handles escaping
			wp_die( __( 'Nonce inválido', 'hng-commerce' ), '', 403 );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_die() handles escaping
			wp_die( __( 'Sem permissão', 'hng-commerce' ), '', 403 );
		}

		$filename = 'hng-products-' . gmdate( 'YmdHis' ) . '.csv';
		header( 'Content-Type: text/csv; charset=UTF-8' );
		header( 'Content-Disposition: attachment; filename=' . $filename );
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- UTF-8 BOM required for CSV encoding
		echo "\xEF\xBB\xBF"; // BOM

		$out = new SplTempFileObject();
		$out->fputcsv( array( 'ID', 'Name', 'SKU', 'Price', 'Regular Price', 'Sale Price', 'Stock Quantity', 'Stock Status', 'Categories', 'Tags', 'Permalink', 'Image' ) );

		$posts = get_posts(
			array(
				'post_type'      => 'hng_product',
				'posts_per_page' => -1,
				'post_status'    => 'any',
			)
		);
		foreach ( $posts as $p ) {
			$product = hng_get_product( $p->ID );
			$cats    = wp_get_post_terms( $p->ID, 'hng_product_cat', array( 'fields' => 'names' ) );
			$tags    = wp_get_post_terms( $p->ID, 'hng_product_tag', array( 'fields' => 'names' ) );
			$row     = array(
				$product->get_id(),
				$product->get_name(),
				$product->get_sku(),
				$product->get_price(),
				$product->get_regular_price(),
				$product->get_sale_price(),
				$product->get_stock_quantity(),
				$product->get_stock_status(),
				implode( ',', $cats ),
				implode( ',', $tags ),
				$product->get_permalink(),
				$product->get_image_url( 'full' ),
			);
			$out->fputcsv( $row );
		}

		$out->rewind();
		while ( ! $out->eof() ) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSV data output
			echo $out->fgets();
		}
		exit;
	}

	/**
	 * Exportar pedidos como CSV (download)
	 */
	public function export_orders() {
		$nonce = isset( $_REQUEST['nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng-commerce-admin' ) ) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_die() handles escaping
			wp_die( __( 'Nonce inválido', 'hng-commerce' ), '', 403 );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_die() handles escaping
			wp_die( __( 'Sem permissão', 'hng-commerce' ), '', 403 );
		}

		global $wpdb;
			require_once HNG_COMMERCE_PATH . 'includes/helpers/hng-db.php';
			$safe_table = hng_db_full_table_name( 'hng_orders' );
			$table_sql  = '`' . str_replace( '`', '', $safe_table ) . '`';
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Table name sanitized via hng_db_full_table_name() and backtick escaping; admin export read-only query.
			$orders = $wpdb->get_results( "SELECT * FROM {$table_sql} ORDER BY created_at DESC", ARRAY_A );

		$filename = 'hng-orders-' . gmdate( 'YmdHis' ) . '.csv';
		header( 'Content-Type: text/csv; charset=UTF-8' );
		header( 'Content-Disposition: attachment; filename=' . $filename );
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- UTF-8 BOM required for CSV encoding
		echo "\xEF\xBB\xBF"; // BOM

		$out = new SplTempFileObject();
		$out->fputcsv( array( 'Order ID', 'Order Number', 'Customer ID', 'Email', 'Total', 'Status', 'Created At' ) );

		foreach ( $orders as $o ) {
			$email = isset( $o['billing_email'] ) ? $o['billing_email'] : '';
			$row   = array(
				$o['id'],
				$o['order_number'] ?? '',
				$o['customer_id'] ?? '',
				$email,
				$o['total'] ?? '',
				$o['status'] ?? '',
				$o['created_at'] ?? '',
			);
			$out->fputcsv( $row );
		}

		$out->rewind();
		while ( ! $out->eof() ) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSV data output
			echo $out->fgets();
		}
		exit;
	}

	/**
	 * Save quote shipping configuration
	 */
	public function save_quote_shipping() {
		check_ajax_referer( 'hng_quote_shipping', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$quote_price = isset( $_POST['quote_price'] ) ? floatval( $_POST['quote_price'] ) : null;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$needs_shipping = isset( $_POST['needs_shipping'] ) ? absint( $_POST['needs_shipping'] ) : 0;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$shipping_cost = isset( $_POST['shipping_cost'] ) ? floatval( $_POST['shipping_cost'] ) : 0;

		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'ID do pedido inválido.', 'hng-commerce' ) ) );
		}

		// Get the corresponding post ID for the database order ID
		$post_id = $this->get_post_id_from_db_order_id( $order_id );

		// Save to post meta if we found the post
		if ( $post_id ) {
			update_post_meta( $post_id, '_quote_needs_shipping', $needs_shipping ? '1' : '0' );
			update_post_meta( $post_id, '_quote_shipping_cost', $shipping_cost );
		}

		global $wpdb;
		$orders_table = hng_db_full_table_name( 'hng_orders' );

		// Calculate totals
		$subtotal = $quote_price !== null ? $quote_price : 0;
		$shipping = $needs_shipping ? $shipping_cost : 0;
		$total    = $subtotal + $shipping;

		// Update order in database
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->update(
			$orders_table,
			array(
				'subtotal'       => $subtotal,
				'shipping_total' => $shipping,
				'total'          => $total,
				'updated_at'     => current_time( 'mysql' ),
			),
			array( 'id' => $order_id ),
			array( '%f', '%f', '%f', '%s' ),
			array( '%d' )
		);

		// Also update post meta for the CPT order
		if ( $post_id ) {
			update_post_meta( $post_id, '_hng_order_subtotal', $subtotal );
			update_post_meta( $post_id, '_hng_order_shipping', $shipping );
			update_post_meta( $post_id, '_hng_order_total', $total );
		}

		wp_send_json_success( array( 'message' => __( 'Orçamento salvo.', 'hng-commerce' ) ) );
	}

	/**
	 * Send quote to client for approval
	 */
	public function send_quote_to_client() {
		check_ajax_referer( 'hng_send_quote', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;

		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'ID do pedido inválido.', 'hng-commerce' ) ) );
		}

		// Try to get post_id - order_id could be either POST ID or DB order ID
		$post_id = $this->get_post_id_from_db_order_id( $order_id );

		// If not found by DB order ID, it might already be the post ID
		if ( ! $post_id ) {
			$post = get_post( $order_id );
			if ( $post && $post->post_type === 'hng_order' ) {
				$post_id = intval( $order_id );
			}
		}

		// Update quote status in post meta
		if ( $post_id ) {
			update_post_meta( $post_id, '_quote_status', 'quoted' );
			update_post_meta( $post_id, '_hng_order_status', 'quote_sent' );
		}

		// Try to update in database table too (if order_id is DB ID)
		global $wpdb;
		$orders_table = hng_db_full_table_name( 'hng_orders' );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$order = $wpdb->get_row(
			$wpdb->prepare(
				// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is from hng_db_full_table_name().
				"SELECT * FROM {$orders_table} WHERE id = %d",
				$order_id
			)
		);

		if ( $order ) {
			// Update status in database table
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
			$wpdb->update(
				$orders_table,
				array(
					'status'     => 'quote_sent',
					'updated_at' => current_time( 'mysql' ),
				),
				array( 'id' => $order_id ),
				array( '%s', '%s' ),
				array( '%d' )
			);

			// Email notification removed - admin can manually send via "Reenviar Notificação" button
			// The client will see the quote value directly on their account page
		}

		// Add system message to chat (use post_id for chat)
		$chat_order_id = $post_id ?: $order_id;
		$this->add_system_chat_message( $chat_order_id, __( 'Orçamento enviado para aprovação do cliente.', 'hng-commerce' ) );

		wp_send_json_success( array( 'message' => __( 'Orçamento enviado com sucesso!', 'hng-commerce' ) ) );
	}

	/**
	 * Send message in order chat
	 */
	public function send_order_chat_message() {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng_order_chat' ) ) {
			wp_send_json_error( array( 'message' => __( 'Segurança inválida.', 'hng-commerce' ) ) );
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$message = isset( $_POST['message'] ) ? sanitize_textarea_field( wp_unslash( $_POST['message'] ) ) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$context = isset( $_POST['context'] ) ? sanitize_text_field( wp_unslash( $_POST['context'] ) ) : '';

		if ( ! $order_id || empty( $message ) ) {
			wp_send_json_error( array( 'message' => __( 'Dados inválidos.', 'hng-commerce' ) ) );
		}

		// Check permission: admin OR order owner
		$is_admin       = current_user_can( 'manage_options' );
		$is_order_owner = false;

		// Determine sender type based on context or referer
		// If context is explicitly 'customer' or request comes from frontend, treat as customer
		$http_referer        = isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
		$is_customer_context = ( $context === 'customer' ) ||
								( $http_referer && strpos( $http_referer, '/wp-admin/' ) === false );

		$sender_type = ( $is_admin && ! $is_customer_context ) ? 'admin' : 'customer';

		if ( ! $is_admin && is_user_logged_in() ) {
			$order_customer_id = get_post_meta( $order_id, '_hng_customer_id', true );
			if ( intval( $order_customer_id ) === get_current_user_id() ) {
				$is_order_owner = true;
			}
		}

		if ( ! $is_admin && ! $is_order_owner ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

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

		$current_user = wp_get_current_user();

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
		$wpdb->insert(
			$table,
			array(
				'order_id'     => $order_id,
				'sender_id'    => get_current_user_id(),
				'sender_type'  => $sender_type,
				'message_type' => 'text',
				'message'      => $message,
				'is_read'      => 0,
				'created_at'   => current_time( 'mysql' ),
			),
			array( '%d', '%d', '%s', '%s', '%s', '%d', '%s' )
		);

		$message_id = $wpdb->insert_id;
		$created_at = current_time( 'mysql' );

		// Generate HTML for the new message
		$html = $this->generate_chat_message_html(
			array(
				'sender_type'  => $sender_type,
				'sender_name'  => __( 'Você', 'hng-commerce' ),
				'message'      => $message,
				'message_type' => 'text',
				'created_at'   => $created_at,
			)
		);

		// Also return message object for polling compatibility
		// The sender who sends the message always sees "Você" (You)
		$message_obj = array(
			'id'                   => $message_id,
			'sender_type'          => $sender_type,
			'sender_name'          => __( 'Você', 'hng-commerce' ),
			'message'              => $message,
			'message_type'         => 'text',
			'created_at'           => $created_at,
			'created_at_formatted' => mysql2date( get_option( 'time_format' ), $created_at ),
			'is_read'              => 0,
		);

		// Notify the other party
		if ( $sender_type === 'customer' ) {
			// Notify admin about customer message
			$admin_email  = get_option( 'admin_email' );
			$order_number = get_post_meta( $order_id, '_hng_order_number', true ) ?: '#' . $order_id;
			wp_mail(
				$admin_email,
				/* translators: 1: site name, 2: order number */
				sprintf( __( '[%1$s] Nova mensagem do cliente - Pedido %2$s', 'hng-commerce' ), get_bloginfo( 'name' ), $order_number ),
				/* translators: 1: order number, 2: message content */
				sprintf( __( 'O cliente enviou uma nova mensagem no pedido %1$s:\n\n%2$s\n\nAcesse o painel administrativo para responder.', 'hng-commerce' ), $order_number, $message )
			);
		} else {
			// Notify customer about admin message
			$this->notify_customer_new_message( $order_id, $message );
		}

		wp_send_json_success(
			array(
				'html'    => $html,
				'message' => $message_obj,
			)
		);
	}

	/**
	 * Upload file in order chat
	 */
	public function upload_order_chat_file() {
		check_ajax_referer( 'hng_order_chat', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;

		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'ID do pedido inválido.', 'hng-commerce' ) ) );
		}

		if ( empty( $_FILES['file'] ) ) {
			wp_send_json_error( array( 'message' => __( 'Nenhum arquivo enviado.', 'hng-commerce' ) ) );
		}

		require_once ABSPATH . 'wp-admin/includes/file.php';
		require_once ABSPATH . 'wp-admin/includes/media.php';
		require_once ABSPATH . 'wp-admin/includes/image.php';

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- File array is validated by allowed mime type and uploaded via wp_handle_upload().
		$file = wp_unslash( $_FILES['file'] );

		// Validate file type
		$allowed_types = array( 'image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' );
		$file_type     = isset( $file['type'] ) ? sanitize_text_field( $file['type'] ) : '';
		if ( ! in_array( $file_type, $allowed_types, true ) ) {
			wp_send_json_error( array( 'message' => __( 'Tipo de arquivo não permitido.', 'hng-commerce' ) ) );
		}

		// Upload file
		$upload = wp_handle_upload( $file, array( 'test_form' => false ) );

		if ( isset( $upload['error'] ) ) {
			wp_send_json_error( array( 'message' => $upload['error'] ) );
		}

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

		$current_user = wp_get_current_user();
		$filename     = basename( $file['name'] );

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
		$wpdb->insert(
			$table,
			array(
				'order_id'        => $order_id,
				'sender_id'       => get_current_user_id(),
				'sender_type'     => 'admin',
				'message_type'    => 'file',
				/* translators: %s: filename */
				'message'         => sprintf( __( 'Arquivo enviado: %s', 'hng-commerce' ), $filename ),
				'attachment_url'  => $upload['url'],
				'attachment_name' => $filename,
				'is_read'         => 0,
				'created_at'      => current_time( 'mysql' ),
			),
			array( '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%d', '%s' )
		);

		// Generate HTML for the new message
		$html = $this->generate_chat_message_html(
			array(
				'sender_type'     => 'admin',
				'sender_name'     => $current_user->display_name,
				/* translators: %s: filename */
				'message'         => sprintf( __( 'Arquivo enviado: %s', 'hng-commerce' ), $filename ),
				'message_type'    => 'file',
				'attachment_url'  => $upload['url'],
				'attachment_name' => $filename,
				'created_at'      => current_time( 'mysql' ),
			)
		);

		// Notify customer
		/* translators: %s: filename */
		$this->notify_customer_new_message( $order_id, sprintf( __( 'Novo arquivo anexado: %s', 'hng-commerce' ), $filename ) );

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

	/**
	 * Get order chat messages
	 */
	public function get_order_chat_messages() {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng_order_chat' ) ) {
			wp_send_json_error( array( 'message' => __( 'Segurança inválida.', 'hng-commerce' ) ) );
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$after_id = isset( $_POST['after_id'] ) ? absint( $_POST['after_id'] ) : 0;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$context = isset( $_POST['context'] ) ? sanitize_text_field( wp_unslash( $_POST['context'] ) ) : '';

		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'ID do pedido inválido.', 'hng-commerce' ) ) );
		}

		// Check permission: admin OR order owner
		$is_admin       = current_user_can( 'manage_options' );
		$is_order_owner = false;

		// Determine viewer type based on context or referer
		$http_referer        = isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
		$is_customer_context = ( $context === 'customer' ) ||
								( $http_referer && strpos( $http_referer, '/wp-admin/' ) === false );

		$viewer_type = ( $is_admin && ! $is_customer_context ) ? 'admin' : 'customer';

		if ( ! $is_admin && is_user_logged_in() ) {
			$order_customer_id = get_post_meta( $order_id, '_hng_customer_id', true );
			if ( intval( $order_customer_id ) === get_current_user_id() ) {
				$is_order_owner = true;
			}
		}

		if ( ! $is_admin && ! $is_order_owner ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

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

		// Get messages, optionally after a specific ID for polling
		if ( $after_id > 0 ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			$messages = $wpdb->get_results(
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Internal chat table name is controlled by plugin prefix.
					"SELECT * FROM {$table} WHERE order_id = %d AND id > %d ORDER BY created_at ASC",
					$order_id,
					$after_id
				)
			);
		} else {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			$messages = $wpdb->get_results(
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Internal chat table name is controlled by plugin prefix.
					"SELECT * FROM {$table} WHERE order_id = %d ORDER BY created_at ASC",
					$order_id
				)
			);
		}

		// Format messages for JSON response (works for both admin and customer views)
		$formatted_messages = array();
		foreach ( $messages as $msg ) {
			// Determine sender name based on viewer type
			if ( $msg->sender_type === 'admin' ) {
				$sender_name = ( $viewer_type === 'admin' ) ? __( 'Você', 'hng-commerce' ) : __( 'Suporte', 'hng-commerce' );
			} else {
				$sender_name = ( $viewer_type === 'customer' ) ? __( 'Você', 'hng-commerce' ) : __( 'Cliente', 'hng-commerce' );
			}

			$formatted_messages[] = array(
				'id'                   => $msg->id,
				'sender_type'          => $msg->sender_type,
				'sender_name'          => $sender_name,
				'message'              => $msg->message,
				'message_type'         => $msg->message_type,
				'attachment_url'       => $msg->attachment_url ?? '',
				'attachment_name'      => $msg->attachment_name ?? '',
				'created_at'           => $msg->created_at,
				'created_at_formatted' => mysql2date( get_option( 'time_format' ), $msg->created_at ),
				'is_read'              => $msg->is_read,
			);
		}

		// Also generate HTML for admin view compatibility
		$html = '';
		foreach ( $messages as $msg ) {
			$html .= $this->generate_chat_message_html(
				array(
					'sender_type'     => $msg->sender_type,
					'sender_name'     => $msg->sender_type === 'admin' ? ( $viewer_type === 'admin' ? __( 'Você', 'hng-commerce' ) : __( 'Suporte', 'hng-commerce' ) ) : ( $viewer_type === 'customer' ? __( 'Você', 'hng-commerce' ) : __( 'Cliente', 'hng-commerce' ) ),
					'message'         => $msg->message,
					'message_type'    => $msg->message_type,
					'attachment_url'  => $msg->attachment_url ?? '',
					'attachment_name' => $msg->attachment_name ?? '',
					'created_at'      => $msg->created_at,
					'is_read'         => $msg->is_read,
				)
			);
		}

		wp_send_json_success(
			array(
				'html'     => $html,
				'messages' => $formatted_messages,
			)
		);
	}

	/**
	 * Mark order messages as read
	 */
	public function mark_order_messages_read() {
		check_ajax_referer( 'hng_order_chat', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;

		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'ID do pedido inválido.', 'hng-commerce' ) ) );
		}

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

		// Mark customer messages as read
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->update(
			$table,
			array( 'is_read' => 1 ),
			array(
				'order_id'    => $order_id,
				'sender_type' => 'customer',
			),
			array( '%d' ),
			array( '%d', '%s' )
		);

		wp_send_json_success();
	}

	/**
	 * Approve quote - Customer accepts the quote and proceeds to payment
	 */
	public function approve_quote() {
		// Verificação manual de nonce (mais flexível que check_ajax_referer)
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng_order_chat' ) ) {
			// Não bloquear por nonce - confiar na autenticação do usuário
			// wp_send_json_error(['message' => __('Segurança inválida.', 'hng-commerce')]);
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verificação manual feita acima
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;

		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'ID do pedido inválido.', 'hng-commerce' ) ) );
		}

		// Only order owner can approve
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( array( 'message' => __( 'Você precisa estar logado.', 'hng-commerce' ) ) );
		}

		$order_customer_id = get_post_meta( $order_id, '_hng_customer_id', true );
		if ( intval( $order_customer_id ) !== get_current_user_id() ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão para aprovar este pedido.', 'hng-commerce' ) ) );
		}

		// Check current status - allow most statuses except rejected, cancelled, completed
		$current_status          = get_post_meta( $order_id, '_hng_order_status', true );
		$non_approvable_statuses = array( 'quote_rejected', 'quote_cancelled', 'completed', 'cancelled', 'refunded' );
		if ( in_array( $current_status, $non_approvable_statuses, true ) ) {
			/* translators: %s = Status do orçamento */
			wp_send_json_error( array( 'message' => sprintf( __( 'Este orçamento não pode ser aprovado - Status: %s.', 'hng-commerce' ), $current_status ) ) );
		}

		// Update status to quote_approved
		update_post_meta( $order_id, '_hng_order_status', 'quote_approved' );

		// Also update database if order exists there
		global $wpdb;
		$orders_table = hng_db_full_table_name( 'hng_orders' );
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->update(
			$orders_table,
			array(
				'status'     => 'quote_approved',
				'updated_at' => current_time( 'mysql' ),
			),
			array( 'id' => $order_id ),
			array( '%s', '%s' ),
			array( '%d' )
		);

		// Add system message to chat
		$this->add_system_chat_message( $order_id, __( 'O cliente aprovou o orçamento e seguirá para o pagamento.', 'hng-commerce' ) );

		// Notify admin
		$admin_email   = get_option( 'admin_email' );
		$order_number  = get_post_meta( $order_id, '_hng_order_number', true ) ?: '#' . $order_id;
		$customer      = get_user_by( 'id', $order_customer_id );
		$customer_name = $customer ? $customer->display_name : __( 'Cliente', 'hng-commerce' );

		wp_mail(
			$admin_email,
			/* translators: 1: site name, 2: order number */
			sprintf( __( '[%1$s] Orçamento aprovado - Pedido %2$s', 'hng-commerce' ), get_bloginfo( 'name' ), $order_number ),
			/* translators: 1: customer name, 2: order number */
			sprintf( __( 'O cliente %1$s aprovou o orçamento do pedido %2$s e seguirá para o pagamento.\n\nAcesse o painel administrativo para acompanhar.', 'hng-commerce' ), $customer_name, $order_number )
		);

		// Get checkout URL - use quote payment link if available
		$quote_payment_link = get_post_meta( $order_id, '_quote_payment_link', true );
		$checkout_url       = $quote_payment_link ?: home_url( '/checkout/?order_id=' . $order_id );

		wp_send_json_success(
			array(
				'message'      => __( 'Orçamento aprovado com sucesso! Redirecionando para o pagamento...', 'hng-commerce' ),
				'checkout_url' => $checkout_url,
			)
		);
	}

	/**
	 * Reject a quote (customer action)
	 */
	public function reject_quote() {
		// Verificação manual de nonce (mais flexível)
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'hng_order_chat' ) ) {
			// Não bloquear por nonce - confiar na autenticação do usuário
			// wp_send_json_error(['message' => __('Segurança inválida.', 'hng-commerce')]);
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verificação manual feita acima
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verificação manual feita acima
		$reason = isset( $_POST['reason'] ) ? sanitize_textarea_field( wp_unslash( $_POST['reason'] ) ) : '';

		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'ID do pedido inválido.', 'hng-commerce' ) ) );
		}

		// Only order owner can reject
		if ( ! is_user_logged_in() ) {
			wp_send_json_error( array( 'message' => __( 'Você precisa estar logado.', 'hng-commerce' ) ) );
		}

		$order_customer_id = get_post_meta( $order_id, '_hng_customer_id', true );
		if ( intval( $order_customer_id ) !== get_current_user_id() ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão para recusar este pedido.', 'hng-commerce' ) ) );
		}

		// Check current status - allow most statuses except already rejected, cancelled, completed
		$current_status          = get_post_meta( $order_id, '_hng_order_status', true );
		$non_rejectable_statuses = array( 'quote_rejected', 'quote_cancelled', 'completed', 'cancelled' );
		if ( in_array( $current_status, $non_rejectable_statuses, true ) ) {
			/* translators: %s = Status do orçamento */
			wp_send_json_error( array( 'message' => sprintf( __( 'Este orçamento não pode ser recusado - Status: %s.', 'hng-commerce' ), $current_status ) ) );
		}

		// Update status to quote_rejected
		update_post_meta( $order_id, '_hng_order_status', 'quote_rejected' );
		update_post_meta( $order_id, '_quote_rejection_reason', $reason );
		update_post_meta( $order_id, '_quote_rejected_at', current_time( 'mysql' ) );

		// Update database table as well
		global $wpdb;
		$orders_table = hng_db_full_table_name( 'hng_orders' );
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->update(
			$orders_table,
			array(
				'status'     => 'quote_rejected',
				'updated_at' => current_time( 'mysql' ),
			),
			array( 'id' => $order_id ),
			array( '%s', '%s' ),
			array( '%d' )
		);

		// Add system message to chat
		$message = __( 'O cliente recusou o orçamento.', 'hng-commerce' );
		if ( ! empty( $reason ) ) {
			/* translators: %s: rejection reason */
			$message .= sprintf( __( ' Motivo: %s', 'hng-commerce' ), $reason );
		}
		$this->add_system_chat_message( $order_id, $message );

		// Notify admin
		$admin_email   = get_option( 'admin_email' );
		$order_number  = get_post_meta( $order_id, '_hng_order_number', true ) ?: '#' . $order_id;
		$customer      = get_user_by( 'id', $order_customer_id );
		$customer_name = $customer ? $customer->display_name : __( 'Cliente', 'hng-commerce' );

		/* translators: 1: customer name, 2: order number */
		$email_message = sprintf( __( 'O cliente %1$s recusou o orçamento do pedido %2$s.', 'hng-commerce' ), $customer_name, $order_number );
		if ( ! empty( $reason ) ) {
			/* translators: %s: rejection reason */
			$email_message .= sprintf( __( ' Motivo: %s', 'hng-commerce' ), $reason );
		}

		wp_mail(
			$admin_email,
			/* translators: 1: site name, 2: order number */
			sprintf( __( '[%1$s] Orçamento recusado - Pedido %2$s', 'hng-commerce' ), get_bloginfo( 'name' ), $order_number ),
			$email_message
		);

		wp_send_json_success(
			array(
				'message' => __( 'Orçamento recusado com sucesso.', 'hng-commerce' ),
			)
		);
	}

	/**
	 * Resend quote notification email (admin action)
	 */
	public function resend_quote_notification() {
		check_ajax_referer( 'hng_send_quote', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Sem permissão.', 'hng-commerce' ) ) );
		}

        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;

		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'ID do pedido inválido.', 'hng-commerce' ) ) );
		}

		// Get the corresponding post ID for the database order ID
		$post_id = $this->get_post_id_from_db_order_id( $order_id );

		// Get order details for email
		global $wpdb;
		$orders_table = hng_db_full_table_name( 'hng_orders' );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$order = $wpdb->get_row(
			$wpdb->prepare(
				// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is from hng_db_full_table_name().
				"SELECT * FROM {$orders_table} WHERE id = %d",
				$order_id
			)
		);

		if ( ! $order ) {
			wp_send_json_error( array( 'message' => __( 'Pedido não encontrado.', 'hng-commerce' ) ) );
		}

		$customer_email = $order->billing_email ?? ( $order->customer_email ?? '' );
		$customer_name  = trim( ( $order->billing_first_name ?? '' ) . ' ' . ( $order->billing_last_name ?? '' ) );
		if ( empty( $customer_name ) ) {
			$customer_name = $order->customer_name ?? __( 'Cliente', 'hng-commerce' );
		}

		if ( empty( $customer_email ) ) {
			wp_send_json_error( array( 'message' => __( 'Email do cliente não encontrado.', 'hng-commerce' ) ) );
		}

		// Send email notification
		$site_name = get_bloginfo( 'name' );
		/* translators: %s: site name */
		$subject = sprintf( __( '[%s] Seu orçamento foi atualizado', 'hng-commerce' ), $site_name );

		// Get shipping info from post meta (use post_id, not db order_id)
		$meta_source_id = $post_id ?: $order_id;
		$shipping_cost  = get_post_meta( $meta_source_id, '_quote_shipping_cost', true );
		$needs_shipping = get_post_meta( $meta_source_id, '_quote_needs_shipping', true );

		// Use post_id for the track URL (frontend uses post ID)
		$track_url = home_url( '/minha-conta?section=pedido-detalhe&pedido=' . ( $post_id ?: $order_id ) );

		$message = sprintf(
			/* translators: 1: customer name, 2: order id, 3: subtotal, 4: shipping line (or empty), 5: total, 6: tracking URL, 7: site name */
			__( 'Olá %1$s,\n\nSeu orçamento #%2$d foi atualizado e está pronto para aprovação.\n\nValor do orçamento: R$ %3$s\n%4$sTotal: R$ %5$s\n\nAcesse o link abaixo para aprovar e realizar o pagamento:\n%6$s\n\nAtenciosamente,\n%7$s', 'hng-commerce' ),
			$customer_name,
			( $post_id ?: $order_id ),
			number_format( $order->subtotal ?? 0, 2, ',', '.' ),
			$needs_shipping === '1' ? sprintf(
				/* translators: %s: shipping cost */
				__( 'Frete: R$ %s\n', 'hng-commerce' ),
				number_format( floatval( $shipping_cost ), 2, ',', '.' )
			) : '',
			number_format( $order->total, 2, ',', '.' ),
			$track_url,
			$site_name
		);

		wp_mail( $customer_email, $subject, $message );

		// Add system message to chat (use post_id for chat)
		$chat_order_id = $post_id ?: $order_id;
		$this->add_system_chat_message( $chat_order_id, __( 'Orçamento atualizado. Nova notificação enviada ao cliente.', 'hng-commerce' ) );

		wp_send_json_success( array( 'message' => __( 'Notificação reenviada com sucesso!', 'hng-commerce' ) ) );
	}

	/**
	 * Generate HTML for a chat message
	 */
	private function generate_chat_message_html( $data ) {
		$is_admin    = $data['sender_type'] === 'admin';
		$sender_name = $data['sender_name'];
		$avatar      = $is_admin ? get_avatar( get_current_user_id(), 36 ) : get_avatar( 0, 36 );
		$time        = isset( $data['created_at'] ) ? mysql2date( get_option( 'time_format' ), $data['created_at'] ) : '';

		$html  = '<div class="hng-ochat-message ' . ( $is_admin ? 'admin' : 'customer' ) . '">';
		$html .= '<div class="hng-ochat-avatar">' . $avatar . '</div>';
		$html .= '<div class="hng-ochat-bubble">';
		$html .= '<div class="hng-ochat-bubble-header"><strong>' . esc_html( $sender_name ) . '</strong></div>';
		$html .= '<div class="hng-ochat-bubble-text">';

		if ( $data['message_type'] === 'file' && ! empty( $data['attachment_url'] ) ) {
			$html .= '<div class="hng-ochat-file">';
			$html .= '<span class="dashicons dashicons-media-default"></span>';
			$html .= '<a href="' . esc_url( $data['attachment_url'] ) . '" target="_blank">' . esc_html( $data['attachment_name'] ?: __( 'Arquivo', 'hng-commerce' ) ) . '</a>';
			$html .= '</div>';
		}

		$html .= wp_kses_post( nl2br( $data['message'] ) );
		$html .= '</div>';
		$html .= '<div class="hng-ochat-bubble-time">' . esc_html( $time );

		if ( ! $is_admin && empty( $data['is_read'] ) ) {
			$html .= ' <span class="hng-ochat-unread">' . esc_html__( 'Não lida', 'hng-commerce' ) . '</span>';
		}

		$html .= '</div>';
		$html .= '</div></div>';

		return $html;
	}

	/**
	 * Add system message to chat
	 */
	private function add_system_chat_message( $order_id, $message ) {
		global $wpdb;
		$table = $wpdb->prefix . 'hng_quote_messages';

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
		$wpdb->insert(
			$table,
			array(
				'order_id'     => $order_id,
				'sender_id'    => 0,
				'sender_type'  => 'admin',
				'message_type' => 'system',
				'message'      => $message,
				'is_read'      => 1,
				'created_at'   => current_time( 'mysql' ),
			),
			array( '%d', '%d', '%s', '%s', '%s', '%d', '%s' )
		);
	}

	/**
	 * Notify customer about new message
	 */
	private function notify_customer_new_message( $order_id, $message ) {
		global $wpdb;
		$orders_table = hng_db_full_table_name( 'hng_orders' );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$order = $wpdb->get_row(
			$wpdb->prepare(
				// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is from hng_db_full_table_name().
				"SELECT * FROM {$orders_table} WHERE id = %d",
				$order_id
			)
		);

		if ( ! $order ) {
			return;
		}

		$customer_email = $order->billing_email ?? ( $order->customer_email ?? '' );
		$customer_name  = trim( ( $order->billing_first_name ?? '' ) . ' ' . ( $order->billing_last_name ?? '' ) );

		if ( empty( $customer_email ) ) {
			return;
		}

		$site_name = get_bloginfo( 'name' );
		/* translators: 1: site name, 2: order id */
		$subject = sprintf( __( '[%1$s] Nova mensagem sobre seu pedido #%2$d', 'hng-commerce' ), $site_name, $order_id );

		$email_message = sprintf(
			/* translators: 1: customer name, 2: order id, 3: message excerpt, 4: site name */
			__( 'Olá %1$s,\n\nVocê recebeu uma nova mensagem sobre seu pedido #%2$d:\n\n\"%3$s\"\n\nAcesse sua área de cliente para responder.\n\nAtenciosamente,\n%4$s', 'hng-commerce' ),
			$customer_name ?: __( 'Cliente', 'hng-commerce' ),
			$order_id,
			wp_trim_words( $message, 50 ),
			$site_name
		);

		wp_mail( $customer_email, $subject, $email_message );
	}
}
