<?php
/**
 * Auditoría centralizada de cambios.
 *
 * @package Logistica
 */

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

/**
 * Persistencia y consulta de eventos de auditoría.
 */
class Logistica_Audit {

	/**
	 * @param array<string, mixed> $entry Datos del evento.
	 * @return int ID insertado o 0.
	 */
	public static function log( $entry ) {
		global $wpdb;

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

		$module_key  = sanitize_key( (string) ( $entry['module_key'] ?? '' ) );
		$entity_type = sanitize_key( (string) ( $entry['entity_type'] ?? '' ) );
		$entity_id   = sanitize_text_field( (string) ( $entry['entity_id'] ?? '' ) );
		$action      = sanitize_key( (string) ( $entry['action'] ?? 'update' ) );

		if ( '' === $module_key || '' === $entity_type || '' === $entity_id ) {
			return 0;
		}

		$meta = $entry['meta'] ?? array();
		if ( ! is_array( $meta ) ) {
			$meta = array();
		}

		$ip = (string) ( $entry['ip_address'] ?? Logistica_Entity_Lifecycle::client_ip() );
		if ( '' !== $ip ) {
			$meta['ip_address'] = $ip;
		}

		$row = array(
			'module_key'     => $module_key,
			'entity_type'    => $entity_type,
			'entity_id'      => $entity_id,
			'action'         => $action,
			'summary'        => sanitize_text_field( (string) ( $entry['summary'] ?? '' ) ),
			'payload_before' => self::encode_payload( $entry['payload_before'] ?? null ),
			'payload_after'  => self::encode_payload( $entry['payload_after'] ?? null ),
			'meta'           => self::encode_payload( $meta ),
			'created_by'     => max( 0, (int) ( $entry['created_by'] ?? get_current_user_id() ) ),
			'created_at'     => current_time( 'mysql', true ),
		);

		$inserted = $wpdb->insert( $table, $row );
		return $inserted ? (int) $wpdb->insert_id : 0;
	}

	/**
	 * @param array<string, mixed> $args Filtros y paginación.
	 * @return array{items: array<int, array<string, mixed>>, total: int}
	 */
	public static function query( $args = array() ) {
		global $wpdb;

		$table = Logistica_Database::table( 'auditoria' );
		if ( ! $table ) {
			return array(
				'items' => array(),
				'total' => 0,
			);
		}

		$where  = array( '1=1' );
		$params = array();

		if ( ! empty( $args['module_key'] ) ) {
			$where[]  = 'module_key = %s';
			$params[] = sanitize_key( (string) $args['module_key'] );
		}

		if ( ! empty( $args['entity_type'] ) ) {
			$where[]  = 'entity_type = %s';
			$params[] = sanitize_key( (string) $args['entity_type'] );
		}

		if ( ! empty( $args['action'] ) ) {
			$where[]  = 'action = %s';
			$params[] = sanitize_key( (string) $args['action'] );
		}

		if ( ! empty( $args['created_by'] ) ) {
			$where[]  = 'created_by = %d';
			$params[] = max( 0, (int) $args['created_by'] );
		}

		if ( ! empty( $args['date_from'] ) ) {
			$where[]  = 'created_at >= %s';
			$params[] = sanitize_text_field( (string) $args['date_from'] ) . ' 00:00:00';
		}

		if ( ! empty( $args['date_to'] ) ) {
			$where[]  = 'created_at <= %s';
			$params[] = sanitize_text_field( (string) $args['date_to'] ) . ' 23:59:59';
		}

		if ( ! empty( $args['search'] ) ) {
			$like     = '%' . $wpdb->esc_like( sanitize_text_field( (string) $args['search'] ) ) . '%';
			$where[]  = '(summary LIKE %s OR entity_id LIKE %s OR module_key LIKE %s)';
			$params[] = $like;
			$params[] = $like;
			$params[] = $like;
		}

		$where_sql = implode( ' AND ', $where );
		$count_sql = "SELECT COUNT(*) FROM {$table} WHERE {$where_sql}"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		if ( $params ) {
			$count_sql = $wpdb->prepare( $count_sql, $params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
		}
		$total = (int) $wpdb->get_var( $count_sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared

		$page     = max( 1, (int) ( $args['page'] ?? 1 ) );
		$page_size = max( 1, min( 100, (int) ( $args['page_size'] ?? 25 ) ) );
		$offset   = ( $page - 1 ) * $page_size;

		$list_sql = "SELECT * FROM {$table} WHERE {$where_sql} ORDER BY created_at DESC, id DESC LIMIT %d OFFSET %d"; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$list_params = array_merge( $params, array( $page_size, $offset ) );
		$rows = $wpdb->get_results( $wpdb->prepare( $list_sql, $list_params ), ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared

		$items = array();
		if ( is_array( $rows ) ) {
			foreach ( $rows as $row ) {
				$items[] = self::format_row( $row );
			}
		}

		return array(
			'items' => $items,
			'total' => $total,
		);
	}

	/**
	 * @param array<string, mixed> $row Fila DB.
	 * @return array<string, mixed>
	 */
	public static function format_row( $row ) {
		$user_id = (int) ( $row['created_by'] ?? 0 );
		$user    = $user_id > 0 ? get_userdata( $user_id ) : false;
		$meta    = json_decode( (string) ( $row['meta'] ?? '' ), true );
		if ( ! is_array( $meta ) ) {
			$meta = array();
		}

		return array(
			'id'             => (int) ( $row['id'] ?? 0 ),
			'module_key'     => (string) ( $row['module_key'] ?? '' ),
			'module_label'   => Logistica_Module_Registry::module_label( (string) ( $row['module_key'] ?? '' ) ),
			'entity_type'    => (string) ( $row['entity_type'] ?? '' ),
			'entity_label'   => Logistica_Module_Registry::entity_label( (string) ( $row['module_key'] ?? '' ), (string) ( $row['entity_type'] ?? '' ) ),
			'entity_id'      => (string) ( $row['entity_id'] ?? '' ),
			'action'         => (string) ( $row['action'] ?? '' ),
			'summary'        => (string) ( $row['summary'] ?? '' ),
			'created_by'     => $user_id,
			'created_by_name'=> $user ? (string) $user->display_name : '',
			'created_at'     => (string) ( $row['created_at'] ?? '' ),
			'ip_address'     => (string) ( $meta['ip_address'] ?? '' ),
		);
	}

	/**
	 * @param mixed $payload Datos a serializar.
	 * @return string|null
	 */
	private static function encode_payload( $payload ) {
		if ( null === $payload || '' === $payload ) {
			return null;
		}

		if ( is_string( $payload ) ) {
			return $payload;
		}

		return wp_json_encode( $payload );
	}
}
