<?php

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

class AVIN_Tracker {
	private $repository;
	private $analytics;
	private $bot_filter;

	public function __construct( AVIN_Views_Repository $repository, AVIN_Analytics_Repository $analytics, AVIN_Bot_Filter $bot_filter ) {
		$this->repository = $repository;
		$this->analytics  = $analytics;
		$this->bot_filter = $bot_filter;
	}

	public function init() {
		add_action( 'template_redirect', array( $this, 'maybe_track_php_view' ), 20 );
		add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue_beacon' ) );
		add_action( 'wp_ajax_avin_track_view', array( $this, 'ajax_track_view' ) );
		add_action( 'wp_ajax_nopriv_avin_track_view', array( $this, 'ajax_track_view' ) );
		add_action( 'wp_ajax_avin_refresh_presence', array( $this, 'ajax_refresh_presence' ) );
		add_action( 'wp_ajax_nopriv_avin_refresh_presence', array( $this, 'ajax_refresh_presence' ) );
		add_action( 'template_redirect', array( $this, 'maybe_track_checkout_start' ), 30 );
		add_action( 'woocommerce_add_to_cart', array( $this, 'track_add_to_cart' ), 10, 6 );
		add_action( 'woocommerce_checkout_order_processed', array( $this, 'track_order' ), 10, 1 );
	}

	public function maybe_track_php_view() {
		if ( 'php' !== get_option( 'avin_tracking_mode', 'beacon' ) ) {
			return;
		}

		$object = $this->current_page_context();
		if ( ! $object || $this->request_excluded() ) {
			return;
		}

		if ( $this->is_tracked_content_type( $object['type'] ) && $object['id'] > 0 ) {
			$this->repository->record_view( $object['id'], $object['type'] );
		}
		$this->analytics->record_page_view( $this->analytics_context( $object ) );
	}

	public function maybe_enqueue_beacon() {
		if ( 'beacon' !== get_option( 'avin_tracking_mode', 'beacon' ) ) {
			return;
		}

		$object = $this->current_page_context();
		if ( ! $object || $this->request_excluded() ) {
			return;
		}

		wp_enqueue_script( 'avin-tracker', AVIN_PLUGIN_URL . 'assets/frontend/tracker.js', array(), AVIN_VERSION, true );
			wp_add_inline_script(
				'avin-tracker',
				'window.AVINTracker=' . wp_json_encode(
					array(
						'url'               => admin_url( 'admin-ajax.php' ),
						'nonce'             => wp_create_nonce( 'avin_track_view' ),
						'id'                => $object['id'],
						'type'              => $object['type'],
						'title'             => $object['title'],
						'pageUrl'           => $object['url'],
						'heartbeatInterval' => 45000,
					)
				) . ';',
				'before'
			);
	}

	public function ajax_track_view() {
		nocache_headers();

		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'avin_track_view' ) ) {
			wp_send_json_error( array( 'message' => 'Invalid tracking nonce.' ), 403 );
		}

		if ( $this->request_excluded() ) {
			wp_send_json_success( array( 'tracked' => false ) );
		}

		$object = $this->page_context_from_request();

		if ( ! $object ) {
			wp_send_json_error( array( 'message' => 'Invalid object.' ), 400 );
		}

		if ( $this->is_tracked_content_type( $object['type'] ) && $object['id'] > 0 ) {
			$this->repository->record_view( $object['id'], $object['type'] );
		}

		$this->analytics->record_page_view( $this->analytics_context( $object ) );
		wp_send_json_success( array( 'tracked' => true ) );
	}

	public function ajax_refresh_presence() {
		nocache_headers();

		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'avin_track_view' ) ) {
			wp_send_json_error( array( 'message' => 'Invalid tracking nonce.' ), 403 );
		}

		if ( $this->request_excluded() ) {
			wp_send_json_success( array( 'refreshed' => false ) );
		}

		$object = $this->page_context_from_request();
		if ( ! $object ) {
			wp_send_json_error( array( 'message' => 'Invalid object.' ), 400 );
		}

		$this->analytics->refresh_presence( $this->analytics_context( $object ) );
		wp_send_json_success( array( 'refreshed' => true ) );
	}

	public function maybe_track_checkout_start() {
		if ( ! function_exists( 'is_checkout' ) || ! is_checkout() || ( function_exists( 'is_order_received_page' ) && is_order_received_page() ) || $this->request_excluded() ) {
			return;
		}

		$session_id = $this->session_cookie();
		$key        = 'avin_checkout_seen_' . substr( hash( 'sha256', $session_id ), 0, 16 );
		if ( get_transient( $key ) ) {
			return;
		}

		set_transient( $key, 1, 30 * MINUTE_IN_SECONDS );
		$this->analytics->record_conversion_event(
			'checkout_start',
			$this->analytics_context(
				array(
					'id'    => 0,
					'type'  => 'checkout',
					'title' => __( 'Checkout', 'apex-view-insights' ),
				)
			)
		);
	}

	public function track_add_to_cart( $cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data ) {
		if ( $this->request_excluded() ) {
			return;
		}

		$product_id = $variation_id ? absint( $variation_id ) : absint( $product_id );
		$this->analytics->record_conversion_event(
			'add_to_cart',
			$this->analytics_context(
				array(
					'id'    => $product_id,
					'type'  => 'product',
					'title' => $product_id ? get_the_title( $product_id ) : __( 'Product', 'apex-view-insights' ),
				)
			)
		);
	}

	public function track_order( $order_id ) {
		$this->analytics->record_conversion_event(
			'order',
			$this->analytics_context(
				array(
					'id'    => absint( $order_id ),
					'type'  => 'shop_order',
					'title' => __( 'Purchase', 'apex-view-insights' ),
				)
			)
		);
	}

	private function current_trackable_object() {
		if ( is_admin() || wp_doing_ajax() || is_feed() || is_preview() || ! is_singular() ) {
			return false;
		}

		$post = get_queried_object();
		if ( ! $post instanceof WP_Post || 'publish' !== $post->post_status ) {
			return false;
		}

		if ( ! in_array( $post->post_type, $this->tracked_post_types(), true ) ) {
			return false;
		}

		return array(
			'id'    => absint( $post->ID ),
			'type'  => sanitize_key( $post->post_type ),
			'title' => get_the_title( $post ),
		);
	}

	private function current_page_context() {
		if ( is_admin() || wp_doing_ajax() || is_feed() || is_preview() ) {
			return false;
		}

		$object = $this->current_trackable_object();
		if ( $object ) {
			$object['url'] = $this->current_url();
			return $object;
		}

		if ( is_singular() ) {
			return false;
		}

		$type       = $this->current_page_type();
		$page_id    = 0;
		$page_label = wp_get_document_title();
		$queried    = get_queried_object();

		if ( $queried instanceof WP_Term ) {
			$page_id    = absint( $queried->term_id );
			$page_label = single_term_title( '', false );
		} elseif ( is_post_type_archive() ) {
			$post_type  = get_query_var( 'post_type' );
			$post_type  = is_array( $post_type ) ? reset( $post_type ) : $post_type;
			$page_label = post_type_archive_title( '', false );
			$type       = 'product' === $post_type ? 'shop' : 'archive';
		}

		if ( '' === $page_label ) {
			$page_label = $this->page_type_label( $type );
		}

		return array(
			'id'    => $page_id,
			'type'  => $type,
			'title' => $page_label,
			'url'   => $this->current_url(),
		);
	}

	private function analytics_context( $context_object ) {
		$visitor_id = $this->visitor_cookie();
		$session_id = $this->session_cookie();
		$source     = $this->source_context();
		$country    = $this->country_context();
		$title      = sanitize_text_field( $context_object['title'] ?? '' );

		return array(
			'visitor_hash'  => hash( 'sha256', $visitor_id . wp_salt( 'auth' ) ),
			'session_hash'  => hash( 'sha256', $session_id . wp_salt( 'secure_auth' ) ),
			'object_id'     => absint( $context_object['id'] ?? 0 ),
			'object_type'   => sanitize_key( $context_object['type'] ?? '' ),
			'object_title'  => $title,
			'page_label'    => sanitize_text_field( $context_object['page_label'] ?? $title ),
			'url'           => ! empty( $context_object['url'] ) ? esc_url_raw( $context_object['url'] ) : $this->current_url(),
			'device_type'   => $this->device_type(),
			'source_type'   => $source['source_type'],
			'social_source' => $source['social_source'],
			'country_code'  => $country['code'],
			'country_name'  => $country['name'],
		);
	}

	private function visitor_cookie() {
		return $this->analytics_cookie( 'avin_visitor_id', YEAR_IN_SECONDS );
	}

	private function session_cookie() {
		return $this->analytics_cookie( 'avin_session_id', 30 * MINUTE_IN_SECONDS );
	}

	private function analytics_cookie( $name, $ttl ) {
		$value = isset( $_COOKIE[ $name ] ) ? sanitize_text_field( wp_unslash( $_COOKIE[ $name ] ) ) : '';
		if ( ! preg_match( '/^[a-f0-9-]{32,64}$/', $value ) ) {
			$value = wp_generate_uuid4();
		}

		$_COOKIE[ $name ] = $value;
		if ( ! headers_sent() ) {
			setcookie(
				$name,
				$value,
				array(
					'expires'  => time() + absint( $ttl ),
					'path'     => COOKIEPATH ? COOKIEPATH : '/',
					'domain'   => COOKIE_DOMAIN ? COOKIE_DOMAIN : '',
					'secure'   => is_ssl(),
					'httponly' => true,
					'samesite' => 'Lax',
				)
			);
		}

		return $value;
	}

	private function source_context() {
		$stored_source = isset( $_COOKIE['avin_source_type'] ) ? sanitize_key( wp_unslash( $_COOKIE['avin_source_type'] ) ) : '';
		$stored_social = isset( $_COOKIE['avin_social_source'] ) ? sanitize_key( wp_unslash( $_COOKIE['avin_social_source'] ) ) : '';
		$referrer      = isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
		$host          = $referrer ? wp_parse_url( $referrer, PHP_URL_HOST ) : '';
		$site_host     = wp_parse_url( home_url(), PHP_URL_HOST );
		$source        = $stored_source ? $stored_source : 'direct';
		$social        = $stored_social;

		if ( $host && $site_host && strtolower( $host ) !== strtolower( $site_host ) ) {
			$source = $this->classify_source_host( $host );
			$social = $this->classify_social_host( $host );
		}

		$this->set_short_cookie( 'avin_source_type', $source, DAY_IN_SECONDS );
		$this->set_short_cookie( 'avin_social_source', $social, DAY_IN_SECONDS );

		return array(
			'source_type'   => $source,
			'social_source' => $social,
		);
	}

	private function set_short_cookie( $name, $value, $ttl ) {
		$_COOKIE[ $name ] = $value;
		if ( ! headers_sent() ) {
			setcookie(
				$name,
				$value,
				array(
					'expires'  => time() + absint( $ttl ),
					'path'     => COOKIEPATH ? COOKIEPATH : '/',
					'domain'   => COOKIE_DOMAIN ? COOKIE_DOMAIN : '',
					'secure'   => is_ssl(),
					'httponly' => true,
					'samesite' => 'Lax',
				)
			);
		}
	}

	private function classify_source_host( $host ) {
		$host = strtolower( (string) $host );
		if ( false !== strpos( $host, 'google.' ) ) {
			return 'google';
		}
		if ( false !== strpos( $host, 'bing.' ) ) {
			return 'bing';
		}
		if ( $this->classify_social_host( $host ) ) {
			return $this->classify_social_host( $host );
		}
		return $host ? 'referral' : 'direct';
	}

	private function classify_social_host( $host ) {
		$host = strtolower( (string) $host );
		$map  = array(
			'facebook.'  => 'facebook',
			'instagram.' => 'instagram',
			'tiktok.'    => 'tiktok',
			'pinterest.' => 'pinterest',
			'twitter.'   => 'x',
			'x.com'      => 'x',
			'youtube.'   => 'youtube',
		);
		foreach ( $map as $needle => $source ) {
			if ( false !== strpos( $host, $needle ) ) {
				return $source;
			}
		}
		return '';
	}

	private function device_type() {
		$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? strtolower( sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) ) : '';
		if ( false !== strpos( $user_agent, 'ipad' ) || false !== strpos( $user_agent, 'tablet' ) ) {
			return 'tablet';
		}
		if ( false !== strpos( $user_agent, 'mobile' ) || false !== strpos( $user_agent, 'iphone' ) || false !== strpos( $user_agent, 'android' ) ) {
			return 'mobile';
		}
		return 'desktop';
	}

	private function country_context() {
		$code = '';
		foreach ( array( 'HTTP_CF_IPCOUNTRY', 'HTTP_X_VERCEL_IP_COUNTRY', 'HTTP_CLOUDFRONT_VIEWER_COUNTRY' ) as $header ) {
			if ( ! empty( $_SERVER[ $header ] ) ) {
				$code = strtoupper( substr( sanitize_text_field( wp_unslash( $_SERVER[ $header ] ) ), 0, 2 ) );
				break;
			}
		}

		$countries = array(
			'US' => 'United States',
			'CA' => 'Canada',
			'GB' => 'United Kingdom',
			'AU' => 'Australia',
		);

		return array(
			'code' => $code ? $code : 'ZZ',
			'name' => isset( $countries[ $code ] ) ? $countries[ $code ] : ( $code ? $code : 'Unknown' ),
		);
	}

	private function current_url() {
		$scheme = is_ssl() ? 'https://' : 'http://';
		$host   = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
		$uri    = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
		return $host ? $scheme . $host . $uri : '';
	}

	private function page_context_from_request() {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
		if ( ! wp_verify_nonce( $nonce, 'avin_track_view' ) ) {
			return false;
		}

		$object_id   = isset( $_POST['object_id'] ) ? absint( $_POST['object_id'] ) : 0;
		$object_type = isset( $_POST['object_type'] ) ? sanitize_key( wp_unslash( $_POST['object_type'] ) ) : '';
		$page_title  = isset( $_POST['page_title'] ) ? sanitize_text_field( wp_unslash( $_POST['page_title'] ) ) : '';
		$page_url    = isset( $_POST['page_url'] ) ? esc_url_raw( wp_unslash( $_POST['page_url'] ) ) : '';

		if ( $this->is_tracked_content_type( $object_type ) ) {
			$post = $object_id ? get_post( $object_id ) : null;
			if ( ! $post || 'publish' !== $post->post_status || $object_type !== $post->post_type ) {
				return false;
			}

			$page_title = get_the_title( $object_id );
		} elseif ( ! in_array( $object_type, $this->tracked_page_types(), true ) ) {
			return false;
		}

		if ( '' === $page_title ) {
			$page_title = $this->page_type_label( $object_type );
		}

		return array(
			'id'    => $object_id,
			'type'  => $object_type,
			'title' => $page_title,
			'url'   => $page_url,
		);
	}

	private function current_page_type() {
		if ( function_exists( 'is_shop' ) && is_shop() ) {
			return 'shop';
		}
		if ( function_exists( 'is_product_category' ) && is_product_category() ) {
			return 'product_category';
		}
		if ( is_category() ) {
			return 'category';
		}
		if ( is_tag() ) {
			return 'tag';
		}
		if ( is_search() ) {
			return 'search';
		}
		if ( is_front_page() ) {
			return 'home';
		}
		if ( is_home() ) {
			return 'blog';
		}
		if ( is_archive() ) {
			return 'archive';
		}

		return 'other';
	}

	private function page_type_label( $type ) {
		$labels = array(
			'archive'          => __( 'Archive', 'apex-view-insights' ),
			'blog'             => __( 'Blog', 'apex-view-insights' ),
			'category'         => __( 'Category', 'apex-view-insights' ),
			'home'             => __( 'Home', 'apex-view-insights' ),
			'other'            => __( 'Store page', 'apex-view-insights' ),
			'page'             => __( 'Page', 'apex-view-insights' ),
			'product_category' => __( 'Product category', 'apex-view-insights' ),
			'search'           => __( 'Search results', 'apex-view-insights' ),
			'shop'             => __( 'Shop', 'apex-view-insights' ),
			'tag'              => __( 'Tag', 'apex-view-insights' ),
		);

		return $labels[ $type ] ?? __( 'Store page', 'apex-view-insights' );
	}

	private function request_excluded() {
		if ( $this->bot_filter->is_bot() ) {
			return true;
		}

		if ( is_user_logged_in() && '1' === (string) get_option( 'avin_exclude_logged_in', '0' ) ) {
			return true;
		}

		if ( is_user_logged_in() && '1' === (string) get_option( 'avin_exclude_admins', '1' ) && current_user_can( 'manage_options' ) ) {
			return true;
		}

		return (bool) apply_filters( 'avin_request_excluded', false );
	}

	private function tracked_post_types() {
		$types = get_option( 'avin_tracked_post_types', array( 'post', 'page', 'product' ) );
		$types = array_values( array_filter( array_map( 'sanitize_key', (array) $types ) ) );
		return ! empty( $types ) ? $types : array( 'post', 'page', 'product' );
	}

	private function is_tracked_content_type( $object_type ) {
		return in_array( sanitize_key( $object_type ), $this->tracked_post_types(), true );
	}

	private function tracked_page_types() {
		return array( 'archive', 'blog', 'category', 'home', 'other', 'product_category', 'search', 'shop', 'tag' );
	}
}
