<?php
/**
 * Historial de paquetes por caja / und por paquete para impresión de etiquetas.
 *
 * @package Logistica
 */

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

/**
 * Persistencia del historial por código de catálogo de etiquetas.
 */
class Logistica_Label_Pack_History {

	/**
	 * Máximo de combinaciones guardadas por referencia.
	 */
	public const MAX_ENTRIES = 8;

	/**
	 * @param string $value Valor numérico del formulario.
	 * @return string Cadena normalizada o vacía si no es válida.
	 */
	public static function normalize_positive_number( $value ) {
		$text = trim( (string) $value );
		if ( '' === $text ) {
			return '';
		}

		$normalized = str_replace( ',', '.', $text );
		if ( ! is_numeric( $normalized ) ) {
			return '';
		}

		$number = (float) $normalized;
		if ( $number <= 0 ) {
			return '';
		}

		return $text;
	}

	/**
	 * @param array<string, mixed> $row Fila DB.
	 * @return array<string, mixed>
	 */
	public static function format_entry_for_client( $row ) {
		if ( ! is_array( $row ) ) {
			return array();
		}

		return array(
			'id'              => (int) ( $row['id'] ?? 0 ),
			'catalog_id'      => (int) ( $row['catalog_id'] ?? 0 ),
			'paquetes'        => (string) ( $row['paquetes'] ?? '' ),
			'und_por_paquete' => (string) ( $row['und_por_paquete'] ?? '' ),
			'last_used_at'    => (string) ( $row['last_used_at'] ?? '' ),
		);
	}

	/**
	 * @param int $catalog_id ID del catálogo de etiquetas.
	 * @param int $limit      Máximo de filas.
	 * @return array<int, array<string, mixed>>
	 */
	public static function get_for_catalog( $catalog_id, $limit = self::MAX_ENTRIES ) {
		global $wpdb;

		$catalog_id = (int) $catalog_id;
		$limit      = max( 1, min( (int) $limit, self::MAX_ENTRIES ) );

		if ( $catalog_id <= 0 || ! Logistica_Label_Product_Catalog::get_by_id( $catalog_id ) ) {
			return array();
		}

		$table = Logistica_Database::table( 'etiqueta_pack_historial' );
		if ( ! $table ) {
			return array();
		}

		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$table} WHERE catalog_id = %d ORDER BY last_used_at DESC, id DESC LIMIT %d", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
				$catalog_id,
				$limit
			),
			ARRAY_A
		);

		if ( ! is_array( $rows ) ) {
			return array();
		}

		return array_values(
			array_filter(
				array_map( array( __CLASS__, 'format_entry_for_client' ), $rows )
			)
		);
	}

	/**
	 * Guarda o actualiza una combinación y devuelve el historial actualizado.
	 *
	 * @param int    $catalog_id      ID del catálogo.
	 * @param string $paquetes        Paquetes por caja.
	 * @param string $und_por_paquete Unidades por paquete.
	 * @param int    $user_id         Usuario que guarda.
	 * @return array<string, mixed>|WP_Error
	 */
	public static function save_entry( $catalog_id, $paquetes, $und_por_paquete, $user_id = 0 ) {
		global $wpdb;

		$catalog_id      = (int) $catalog_id;
		$paquetes        = self::normalize_positive_number( $paquetes );
		$und_por_paquete = self::normalize_positive_number( $und_por_paquete );
		$user_id         = max( 0, (int) $user_id );

		if ( $catalog_id <= 0 || ! Logistica_Label_Product_Catalog::get_by_id( $catalog_id ) ) {
			return new WP_Error( 'invalid_catalog', __( 'Registro de etiqueta no válido.', 'logistica' ) );
		}

		if ( '' === $paquetes || '' === $und_por_paquete ) {
			return new WP_Error( 'invalid_values', __( 'Indica paquetes por caja y unidades por paquete válidos.', 'logistica' ) );
		}

		$table = Logistica_Database::table( 'etiqueta_pack_historial' );
		if ( ! $table ) {
			return new WP_Error( 'missing_table', __( 'No se pudo acceder al historial.', 'logistica' ) );
		}

		$now = current_time( 'mysql', true );

		$existing_id = (int) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT id FROM {$table} WHERE catalog_id = %d AND paquetes = %s AND und_por_paquete = %s LIMIT 1", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
				$catalog_id,
				$paquetes,
				$und_por_paquete
			)
		);

		if ( $existing_id > 0 ) {
			$wpdb->update(
				$table,
				array(
					'last_used_at' => $now,
					'created_by'   => $user_id > 0 ? $user_id : get_current_user_id(),
				),
				array( 'id' => $existing_id ),
				array( '%s', '%d' ),
				array( '%d' )
			);
		} else {
			$wpdb->insert(
				$table,
				array(
					'catalog_id'      => $catalog_id,
					'paquetes'        => $paquetes,
					'und_por_paquete' => $und_por_paquete,
					'last_used_at'    => $now,
					'created_by'      => $user_id > 0 ? $user_id : get_current_user_id(),
				),
				array( '%d', '%s', '%s', '%s', '%d' )
			);
		}

		self::trim_catalog_history( $catalog_id );

		$entries = self::get_for_catalog( $catalog_id );

		return array(
			'entry'   => ! empty( $entries ) ? $entries[0] : array(),
			'entries' => $entries,
		);
	}

	/**
	 * Conserva solo las combinaciones más recientes por catálogo.
	 *
	 * @param int $catalog_id ID del catálogo.
	 * @return void
	 */
	private static function trim_catalog_history( $catalog_id ) {
		global $wpdb;

		$catalog_id = (int) $catalog_id;
		if ( $catalog_id <= 0 ) {
			return;
		}

		$table = Logistica_Database::table( 'etiqueta_pack_historial' );
		if ( ! $table ) {
			return;
		}

		$keep_ids = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT id FROM {$table} WHERE catalog_id = %d ORDER BY last_used_at DESC, id DESC LIMIT %d", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
				$catalog_id,
				self::MAX_ENTRIES
			)
		);

		if ( ! is_array( $keep_ids ) || empty( $keep_ids ) ) {
			return;
		}

		$keep_ids = array_map( 'intval', $keep_ids );
		$placeholders = implode( ',', array_fill( 0, count( $keep_ids ), '%d' ) );

		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$table} WHERE catalog_id = %d AND id NOT IN ({$placeholders})", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPlaceholder
				array_merge( array( $catalog_id ), $keep_ids )
			)
		);
	}
}
