<?php
/**
 * File containing \Crowdsignal_Forms\Gateways\Post_Poll_Meta_Gateway
 *
 * @package crowdsignal-forms/Gateways
 * @since 0.9.0
 */

namespace Crowdsignal_Forms\Gateways;

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

/**
 * Class Post_Poll_Meta_Gateway
 *
 * @package Crowdsignal_Forms\Gateways
 */
class Post_Poll_Meta_Gateway {
	/**
	 * Prefix for meta entries.
	 */
	const META_PREFIX = '_cs_poll_';

	/**
	 * Get a client id's associated poll data.
	 *
	 * @param int|null $post_id   The post we have embedded the poll, or null to search all posts.
	 * @param string   $client_id The uuid we assigned to the poll block.
	 * @return array
	 */
	public function get_poll_data_for_poll_client_id( $post_id, $client_id ) {
		global $wpdb;

		if ( null === $client_id ) {
			return array();
		}

		$poll_meta_key = $this->get_poll_meta_key( $client_id );

		if ( null === $post_id ) {
			// Search across all posts for this client_id.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
			$row = $wpdb->get_row(
				$wpdb->prepare(
					"SELECT meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s LIMIT 1",
					$poll_meta_key
				)
			);

			if ( $row && ! empty( $row->meta_value ) ) {
				$data = maybe_unserialize( $row->meta_value );
				return is_array( $data ) ? $data : array();
			}

			return array();
		}

		$meta_value = get_post_meta( $post_id, $poll_meta_key, true );

		return is_array( $meta_value ) ? $meta_value : array();
	}

	/**
	 * Update a client id's associated poll data.
	 *
	 * @param int    $post_id   The post.
	 * @param string $client_id The client id.
	 * @param array  $data      Data as array.
	 *
	 * @return bool|int
	 */
	public function update_poll_data_for_client_id( $post_id, $client_id, $data ) {
		return update_post_meta( $post_id, $this->get_poll_meta_key( $client_id ), $data );
	}

	/**
	 * Return the meta key for a poll block client ID.
	 *
	 * @param string $poll_id_on_block The client id.
	 * @return string
	 */
	private function get_poll_meta_key( $poll_id_on_block ) {
		return self::META_PREFIX . $poll_id_on_block;
	}

	/**
	 * Get the original location (post and/or comment) where a client_id is mapped.
	 *
	 * Algorithm:
	 * 1. Find _cs_poll_{client_id} meta → gives post_id + poll_id
	 * 2. Check if poll_id is in _crowdsignal_forms_poll_ids on that post
	 * 3. If yes → originated in post
	 * 4. If no → scan _crowdsignal_forms_comment_poll_ids_{*} to find comment
	 *
	 * @since 1.8.0
	 *
	 * @param string $client_id The poll client ID.
	 * @return array{post_id: int|null, comment_id: int|null} The original location.
	 */
	public function get_original_location_for_client_id( $client_id ) {
		global $wpdb;

		$poll_meta_key = $this->get_poll_meta_key( $client_id );

		// Step 1: Get the meta row (post_id + meta_value with poll_id).
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
		$result = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s LIMIT 1",
				$poll_meta_key
			)
		);

		if ( ! $result ) {
			return array(
				'post_id'    => null,
				'comment_id' => null,
			);
		}

		$post_id   = (int) $result->post_id;
		$poll_data = maybe_unserialize( $result->meta_value );
		$poll_id   = isset( $poll_data['id'] ) ? (int) $poll_data['id'] : 0;

		if ( ! $poll_id ) {
			// No platform poll_id yet - poll hasn't been synced.
			return array(
				'post_id'    => $post_id,
				'comment_id' => null,
			);
		}

		// Step 2: Check if poll_id is in post's _crowdsignal_forms_poll_ids.
		$post_poll_ids = get_post_meta( $post_id, '_crowdsignal_forms_poll_ids', true );
		if ( is_array( $post_poll_ids ) && in_array( $poll_id, $post_poll_ids, true ) ) {
			// Poll is in the post directly.
			return array(
				'post_id'    => $post_id,
				'comment_id' => null,
			);
		}

		// Step 3: Scan comment poll metas to find which comment has this poll_id.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
		$comment_metas = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT meta_key, meta_value FROM {$wpdb->postmeta}
				 WHERE post_id = %d AND meta_key LIKE %s AND meta_value LIKE %s",
				$post_id,
				$wpdb->esc_like( '_crowdsignal_forms_comment_poll_ids_' ) . '%',
				'%' . $wpdb->esc_like( ':' . $poll_id . ';' ) . '%'
			)
		);

		foreach ( $comment_metas as $meta ) {
			$comment_poll_ids = maybe_unserialize( $meta->meta_value );
			if ( is_array( $comment_poll_ids ) && in_array( $poll_id, $comment_poll_ids, true ) ) {
				// Extract comment_id from meta_key suffix.
				$comment_id = (int) str_replace( '_crowdsignal_forms_comment_poll_ids_', '', $meta->meta_key );
				return array(
					'post_id'    => $post_id,
					'comment_id' => $comment_id,
				);
			}
		}

		// Fallback: poll_id not found in either - treat as post origin.
		return array(
			'post_id'    => $post_id,
			'comment_id' => null,
		);
	}
}