<?php
/**
 * Helpful vote storage for reviews.
 *
 * @package Ugcify\Review
 */

namespace Ugcify\Review;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class HelpfulVotes
 */
class HelpfulVotes {
	const META_KEY = '_ugcify_helpful_votes';

	/**
	 * Review meta handler.
	 *
	 * @var ReviewMeta
	 */
	private $meta;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->meta = new ReviewMeta();
	}

	/**
	 * Get vote summary for a review.
	 *
	 * @param int $review_id Review ID.
	 * @param int $user_id Current user ID.
	 * @return array<string,mixed>
	 */
	public function get_summary( $review_id, $user_id = 0 ) {
		$votes                 = $this->get_votes( $review_id );
		$helpful_count         = 0;
		$not_helpful_count     = 0;
		$current_user_reaction = '';

		foreach ( $votes as $voter_id => $reaction ) {
			if ( 'helpful' === $reaction ) {
				++$helpful_count;
			} elseif ( 'not_helpful' === $reaction ) {
				++$not_helpful_count;
			}

			if ( $user_id > 0 && (int) $voter_id === (int) $user_id ) {
				$current_user_reaction = $reaction;
			}
		}

		return array(
			'helpful_count'        => $helpful_count,
			'not_helpful_count'    => $not_helpful_count,
			'current_user_reaction' => $current_user_reaction,
		);
	}

	/**
	 * Toggle a user's vote.
	 *
	 * @param int    $review_id Review ID.
	 * @param int    $user_id User ID.
	 * @param string $reaction Reaction.
	 * @return array<string,mixed>
	 */
	public function toggle_vote( $review_id, $user_id, $reaction ) {
		$review_id = absint( $review_id );
		$user_id   = absint( $user_id );
		$reaction  = sanitize_key( (string) $reaction );

		if ( ! in_array( $reaction, array( 'helpful', 'not_helpful' ), true ) || $review_id <= 0 || $user_id <= 0 ) {
			return $this->get_summary( $review_id, $user_id );
		}

		$votes      = $this->get_votes( $review_id );
		$user_key   = (string) $user_id;
		$old_vote   = isset( $votes[ $user_key ] ) ? $votes[ $user_key ] : '';
		$new_vote   = $old_vote === $reaction ? '' : $reaction;

		if ( '' === $new_vote ) {
			unset( $votes[ $user_key ] );
		} else {
			$votes[ $user_key ] = $new_vote;
		}

		$this->meta->update_meta( $review_id, self::META_KEY, $votes );

		return $this->get_summary( $review_id, $user_id );
	}

	/**
	 * Get normalized votes for a review.
	 *
	 * @param int $review_id Review ID.
	 * @return array<string,string>
	 */
	private function get_votes( $review_id ) {
		$raw_votes = $this->meta->get_meta( absint( $review_id ), self::META_KEY, true );
		$votes     = array();

		if ( ! is_array( $raw_votes ) ) {
			return $votes;
		}

		foreach ( $raw_votes as $user_id => $reaction ) {
			$user_id  = absint( $user_id );
			$reaction = sanitize_key( (string) $reaction );

			if ( $user_id > 0 && in_array( $reaction, array( 'helpful', 'not_helpful' ), true ) ) {
				$votes[ (string) $user_id ] = $reaction;
			}
		}

		return $votes;
	}
}
