<?php
/**
 * Analytics REST controller: event tracking and reporting.
 *
 * @package Vist360
 */

namespace Vist360\Rest;

defined( 'ABSPATH' ) || exit;

use Vist360\Domain\Settings;
use Vist360\Domain\TourPostType;

/**
 * Records anonymous viewer events and serves aggregated stats.
 */
class AnalyticsController {

	const REST_NAMESPACE = 'vist360/v1';

	/**
	 * Event types accepted from the frontend.
	 *
	 * @var string[]
	 */
	const EVENT_TYPES = array( 'view', 'scene_change', 'hotspot_click', 'share' );

	/**
	 * Hook registrations.
	 */
	public function register_hooks() {
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
	}

	/**
	 * Register REST routes.
	 */
	public function register_routes() {
		register_rest_route(
			self::REST_NAMESPACE,
			'/track',
			array(
				'methods'             => \WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'track_event' ),
				'permission_callback' => '__return_true',
				'args'                => array(
					'tour_id'     => array(
						'type'     => 'integer',
						'required' => true,
						'minimum'  => 1,
					),
					'event'       => array(
						'type'     => 'string',
						'required' => true,
						'enum'     => self::EVENT_TYPES,
					),
					'scene_index' => array(
						'type'    => 'integer',
						'default' => 0,
						'minimum' => 0,
					),
				),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/analytics',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_stats' ),
				'permission_callback' => function () {
					return current_user_can( 'edit_posts' );
				},
				'args'                => array(
					'days'    => array(
						'type'    => 'integer',
						'default' => 30,
						'minimum' => 1,
						'maximum' => 365,
					),
					'tour_id' => array(
						'type'    => 'integer',
						'default' => 0,
						'minimum' => 0,
					),
				),
			)
		);
	}

	/**
	 * Record a viewer event.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function track_event( $request ) {
		$settings = Settings::get();

		if ( ! $settings['analytics_enabled'] ) {
			return rest_ensure_response( array( 'tracked' => false ) );
		}

		$tour_id = (int) $request['tour_id'];
		$post    = get_post( $tour_id );

		if ( ! $post || TourPostType::POST_TYPE !== $post->post_type || 'publish' !== $post->post_status ) {
			return new \WP_Error(
				'vist360_invalid_tour',
				__( 'Tour not found.', 'vistour-virtual-tour-builder' ),
				array( 'status' => 404 )
			);
		}

		global $wpdb;

		// Anonymous daily visitor hash: no PII stored, IP is never persisted.
		$ip_address   = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
		$visitor_hash = md5( $ip_address . wp_date( 'Y-m-d' ) . wp_salt( 'nonce' ) );
		$event        = sanitize_key( $request['event'] );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom analytics table.
		$wpdb->insert(
			$wpdb->prefix . 'vist360_events',
			array(
				'tour_id'      => $tour_id,
				'event_type'   => $event,
				'scene_index'  => (int) $request['scene_index'],
				'visitor_hash' => $visitor_hash,
				'created_at'   => current_time( 'mysql', true ),
			),
			array( '%d', '%s', '%d', '%s', '%s' )
		);

		if ( 'view' === $event ) {
			$views = (int) get_post_meta( $tour_id, '_vist360_views', true );
			update_post_meta( $tour_id, '_vist360_views', $views + 1 );
		}

		return rest_ensure_response( array( 'tracked' => true ) );
	}

	/**
	 * Aggregated stats for the admin dashboard.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response
	 */
	public function get_stats( $request ) {
		global $wpdb;

		$days    = (int) $request['days'];
		$tour_id = (int) $request['tour_id'];
		$since   = gmdate( 'Y-m-d H:i:s', strtotime( "-{$days} days" ) );
		$table   = $wpdb->prefix . 'vist360_events';

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Custom analytics table.
		$totals = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT
					SUM(event_type = 'view') AS views,
					COUNT(DISTINCT CASE WHEN event_type = 'view' THEN visitor_hash END) AS visitors,
					SUM(event_type = 'hotspot_click') AS hotspot_clicks,
					SUM(event_type = 'share') AS shares
				FROM %i
				WHERE created_at >= %s AND ( %d = 0 OR tour_id = %d )",
				$table,
				$since,
				$tour_id,
				$tour_id
			),
			ARRAY_A
		);

		$daily = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT DATE(created_at) AS day, SUM(event_type = 'view') AS views
				FROM %i
				WHERE created_at >= %s AND ( %d = 0 OR tour_id = %d )
				GROUP BY DATE(created_at)
				ORDER BY day ASC",
				$table,
				$since,
				$tour_id,
				$tour_id
			),
			ARRAY_A
		);

		$top_tours = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT tour_id, SUM(event_type = 'view') AS views, SUM(event_type = 'hotspot_click') AS hotspot_clicks
				FROM %i
				WHERE created_at >= %s AND ( %d = 0 OR tour_id = %d )
				GROUP BY tour_id
				ORDER BY views DESC
				LIMIT 10",
				$table,
				$since,
				$tour_id,
				$tour_id
			),
			ARRAY_A
		);
		// phpcs:enable

		foreach ( $top_tours as &$row ) {
			$row['title'] = get_the_title( (int) $row['tour_id'] );
		}
		unset( $row );

		return rest_ensure_response(
			array(
				'totals'    => array(
					'views'          => (int) ( $totals['views'] ?? 0 ),
					'visitors'       => (int) ( $totals['visitors'] ?? 0 ),
					'hotspot_clicks' => (int) ( $totals['hotspot_clicks'] ?? 0 ),
					'shares'         => (int) ( $totals['shares'] ?? 0 ),
				),
				'daily'     => $daily,
				'top_tours' => $top_tours,
			)
		);
	}
}
