<?php

declare(strict_types=1);

namespace Australcode\Rewards\Infrastructure\Wallet;

use Australcode\Rewards\Domain\Wallet\Balance;
use Australcode\Rewards\Domain\Wallet\BalanceRepository;
use Australcode\Rewards\Infrastructure\Database\Schema;

defined( 'ABSPATH' ) || exit;

/**
 * wp_acrwd_balances-backed balance repository. Uses an atomic upsert
 * (INSERT ... ON DUPLICATE KEY UPDATE) so concurrent order completions for the
 * same user don't lose writes.
 */
final class CustomTableBalanceRepository implements BalanceRepository {

	public function find( int $user_id ): Balance {
		global $wpdb;
		$table = Schema::table_name( Schema::TABLE_BALANCES );

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table name from internal Schema constant.
		$row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM `{$table}` WHERE user_id = %d", $user_id ), ARRAY_A );

		return is_array( $row ) ? Balance::from_row( $row ) : Balance::empty( $user_id );
	}

	public function save( Balance $balance ): void {
		global $wpdb;
		$table = Schema::table_name( Schema::TABLE_BALANCES );
		$now   = current_time( 'mysql', true );

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table name from internal Schema constant; values are bound.
		$wpdb->query(
			$wpdb->prepare(
				"INSERT INTO `{$table}`
					(user_id, points_balance, lifetime_earned, lifetime_redeemed, tier_id, updated_at)
				VALUES (%d, %d, %d, %d, %s, %s)
				ON DUPLICATE KEY UPDATE
					points_balance = %d,
					lifetime_earned = %d,
					lifetime_redeemed = %d,
					tier_id = %s,
					updated_at = %s",
				$balance->user_id,
				$balance->points_balance,
				$balance->lifetime_earned,
				$balance->lifetime_redeemed,
				$balance->tier_id,
				$now,
				$balance->points_balance,
				$balance->lifetime_earned,
				$balance->lifetime_redeemed,
				$balance->tier_id,
				$now
			)
		);
	}
}
