<?php
/**
 * Traffic attribution parsing and channel classification.
 *
 * @package Niwa_AI
 */

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

class Niwa_AI_Traffic_Attribution {

	const SESSION_COOKIE = 'niwa_ai_traffic_session';
	const ATTR_COOKIE    = 'niwa_ai_traffic_attr';

	public static function allowed_event_types() {
		return array(
			'pageview',
			'engaged_view',
			'scroll_depth',
			'outbound_click',
			'blog_read',
			'product_view',
			'add_to_cart',
			'begin_checkout',
			'lead',
			'chat_open',
			'chat_message',
			'order',
		);
	}

	public static function normalize_event( $event, $server = array() ) {
		if ( ! is_array( $event ) ) {
			return null;
		}

		$event_type = isset( $event['event_type'] ) ? sanitize_key( $event['event_type'] ) : '';
		if ( ! in_array( $event_type, self::allowed_event_types(), true ) ) {
			return null;
		}

		$page_url     = self::clean_url( $event['page_url'] ?? home_url( '/' ) );
		$referrer_url = self::clean_url( $event['referrer_url'] ?? '' );
		$page_path    = self::path_from_url( $page_url );
		$ref_host     = self::host_from_url( $referrer_url );
		$site_host    = self::host_from_url( home_url( '/' ) );
		$query        = self::query_from_url( $page_url );
		$utm          = self::extract_utm( $query, $event );
		$click_id     = self::extract_click_id( $query, $event );
		$user_agent   = isset( $server['HTTP_USER_AGENT'] ) ? (string) $server['HTTP_USER_AGENT'] : '';
		$source       = $utm['source'];
		$medium       = $utm['medium'];

		if ( '' === $source && '' !== $ref_host && $ref_host !== $site_host ) {
			$source = self::source_from_referrer_host( $ref_host );
		}
		if ( '' === $medium && '' !== $ref_host && $ref_host !== $site_host ) {
			$medium = self::medium_from_referrer_host( $ref_host );
		}
		if ( '' === $source && '' !== $click_id['name'] ) {
			$source = self::source_from_click_id( $click_id['name'] );
		}
		if ( '' === $medium && '' !== $click_id['name'] ) {
			$medium = 'paid';
		}

		$channel = self::classify_channel( $source, $medium, $ref_host, $site_host, $click_id['name'] );

		$session_id = self::sanitize_id( $event['session_id'] ?? self::cookie_value( self::SESSION_COOKIE ) );
		if ( '' === $session_id ) {
			$session_id = 'traffic_' . str_replace( '-', '', self::uuid() );
		}

		$visitor_id = self::sanitize_id( $event['visitor_id'] ?? '' );
		if ( '' === $visitor_id ) {
			$visitor_id = $session_id;
		}

		$occurred_at = self::normalize_datetime( $event['occurred_at'] ?? '' );
		$meta        = isset( $event['meta'] ) && is_array( $event['meta'] ) ? $event['meta'] : array();

		return array(
			'event_id'        => self::sanitize_id( $event['event_id'] ?? '' ),
			'event_type'      => $event_type,
			'session_id'      => substr( $session_id, 0, 96 ),
			'visitor_id'      => substr( $visitor_id, 0, 96 ),
			'occurred_at'     => $occurred_at,
			'page_url'        => $page_url,
			'page_path'       => substr( $page_path, 0, 255 ),
			'page_title'      => sanitize_text_field( (string) ( $event['page_title'] ?? '' ) ),
			'referrer_url'    => $referrer_url,
			'referrer_host'   => substr( sanitize_text_field( $ref_host ), 0, 191 ),
			'source'          => substr( sanitize_key( $source ), 0, 80 ),
			'medium'          => substr( sanitize_key( $medium ), 0, 80 ),
			'campaign'        => substr( sanitize_text_field( $utm['campaign'] ), 0, 191 ),
			'term'            => substr( sanitize_text_field( $utm['term'] ), 0, 191 ),
			'content'         => substr( sanitize_text_field( $utm['content'] ), 0, 191 ),
			'click_id_name'   => substr( sanitize_key( $click_id['name'] ), 0, 40 ),
			'click_id_value'  => substr( sanitize_text_field( $click_id['value'] ), 0, 191 ),
			'channel'         => substr( sanitize_key( $channel ), 0, 60 ),
			'device_type'     => self::device_type( $user_agent ),
			'user_agent_hash' => self::hash_value( $user_agent ),
			'ip_hash'         => self::hash_value( Niwa_AI_Session_Utils::get_client_ip() ),
			'value'           => self::money_value( $event['value'] ?? null ),
			'order_id'        => isset( $event['order_id'] ) ? absint( $event['order_id'] ) : 0,
			'meta'            => $meta,
		);
	}

	public static function classify_channel( $source, $medium, $referrer_host = '', $site_host = '', $click_id_name = '' ) {
		$source        = strtolower( (string) $source );
		$medium        = strtolower( (string) $medium );
		$referrer_host = strtolower( (string) $referrer_host );
		$site_host     = strtolower( (string) $site_host );

		if ( '' !== $click_id_name || preg_match( '/^(cpc|ppc|paid|paid_social|paid-search|display|cp[amv])$/', $medium ) ) {
			return self::is_social_source( $source ) ? 'paid_social' : 'paid_search';
		}
		if ( self::is_email_medium( $medium ) || self::is_email_source( $source ) ) {
			return 'email';
		}
		if ( self::is_social_source( $source ) || self::is_social_source( $referrer_host ) || false !== strpos( $medium, 'social' ) ) {
			return 'organic_social';
		}
		if ( self::is_search_host( $referrer_host ) || 'organic' === $medium ) {
			return 'organic_search';
		}
		if ( '' !== $referrer_host && $referrer_host !== $site_host ) {
			return 'referral';
		}
		if ( '' !== $source || '' !== $medium ) {
			return 'campaign';
		}
		return 'direct';
	}

	public static function attribution_from_cookie() {
		$raw = self::cookie_value( self::ATTR_COOKIE );
		if ( '' === $raw ) {
			return array();
		}
		$decoded = json_decode( rawurldecode( $raw ), true );
		return is_array( $decoded ) ? $decoded : array();
	}

	private static function extract_utm( array $query, array $event ) {
		return array(
			'source'   => self::param( 'utm_source', $query, $event ),
			'medium'   => self::param( 'utm_medium', $query, $event ),
			'campaign' => self::param( 'utm_campaign', $query, $event ),
			'term'     => self::param( 'utm_term', $query, $event ),
			'content'  => self::param( 'utm_content', $query, $event ),
		);
	}

	private static function extract_click_id( array $query, array $event ) {
		foreach ( array( 'gclid', 'gbraid', 'wbraid', 'fbclid', 'msclkid', 'ttclid' ) as $key ) {
			$value = self::param( $key, $query, $event );
			if ( '' !== $value ) {
				return array( 'name' => $key, 'value' => $value );
			}
		}
		return array( 'name' => '', 'value' => '' );
	}

	private static function param( $key, array $query, array $event ) {
		if ( isset( $event[ $key ] ) && '' !== (string) $event[ $key ] ) {
			return sanitize_text_field( (string) $event[ $key ] );
		}
		return isset( $query[ $key ] ) ? sanitize_text_field( (string) $query[ $key ] ) : '';
	}

	private static function query_from_url( $url ) {
		$query = parse_url( (string) $url, PHP_URL_QUERY );
		if ( ! is_string( $query ) || '' === $query ) {
			return array();
		}
		parse_str( $query, $out );
		return is_array( $out ) ? $out : array();
	}

	private static function path_from_url( $url ) {
		$path = parse_url( (string) $url, PHP_URL_PATH );
		return is_string( $path ) && '' !== $path ? $path : '/';
	}

	private static function host_from_url( $url ) {
		$host = parse_url( (string) $url, PHP_URL_HOST );
		return is_string( $host ) ? strtolower( preg_replace( '/^www\./', '', $host ) ) : '';
	}

	private static function clean_url( $url ) {
		$url = trim( (string) $url );
		if ( '' === $url ) {
			return '';
		}
		if ( function_exists( 'esc_url_raw' ) ) {
			return esc_url_raw( $url );
		}
		return filter_var( $url, FILTER_SANITIZE_URL );
	}

	private static function normalize_datetime( $value ) {
		$value = trim( (string) $value );
		if ( '' !== $value ) {
			$ts = strtotime( $value );
			if ( false !== $ts ) {
				return gmdate( 'Y-m-d H:i:s', $ts );
			}
		}
		return current_time( 'mysql' );
	}

	private static function cookie_value( $key ) {
		if ( empty( $_COOKIE[ $key ] ) ) {
			return '';
		}
		return sanitize_text_field( wp_unslash( $_COOKIE[ $key ] ) );
	}

	private static function sanitize_id( $value ) {
		return preg_replace( '/[^a-zA-Z0-9_\-:.]/', '', (string) $value ) ?? '';
	}

	private static function hash_value( $value ) {
		$value = (string) $value;
		if ( '' === $value ) {
			return '';
		}
		$salt = defined( 'AUTH_SALT' ) ? AUTH_SALT : ( defined( 'NIWA_AI_VERSION' ) ? NIWA_AI_VERSION : 'niwa-ai' );
		return hash_hmac( 'sha256', $value, $salt );
	}

	private static function money_value( $value ) {
		if ( null === $value || '' === $value ) {
			return null;
		}
		$normalized = preg_replace( '/[^0-9,\.\-]/', '', (string) $value );
		$normalized = str_replace( ',', '.', (string) $normalized );
		return is_numeric( $normalized ) ? (float) $normalized : null;
	}

	private static function device_type( $ua ) {
		$ua = strtolower( (string) $ua );
		if ( preg_match( '/tablet|ipad/', $ua ) ) {
			return 'tablet';
		}
		if ( preg_match( '/mobile|iphone|android/', $ua ) ) {
			return 'mobile';
		}
		return 'desktop';
	}

	private static function source_from_click_id( $name ) {
		if ( in_array( $name, array( 'fbclid' ), true ) ) {
			return 'facebook';
		}
		if ( in_array( $name, array( 'msclkid' ), true ) ) {
			return 'bing';
		}
		if ( in_array( $name, array( 'ttclid' ), true ) ) {
			return 'tiktok';
		}
		return 'google';
	}

	private static function source_from_referrer_host( $host ) {
		$host = strtolower( (string) $host );
		if ( self::is_search_host( $host ) ) {
			return preg_replace( '/\..*$/', '', $host );
		}
		foreach ( array( 'facebook', 'instagram', 'tiktok', 'linkedin', 'twitter', 'x.com', 'youtube', 'pinterest' ) as $source ) {
			if ( false !== strpos( $host, $source ) ) {
				return 'x.com' === $source ? 'twitter' : $source;
			}
		}
		return $host;
	}

	private static function medium_from_referrer_host( $host ) {
		if ( self::is_search_host( $host ) ) {
			return 'organic';
		}
		if ( self::is_social_source( $host ) ) {
			return 'social';
		}
		return 'referral';
	}

	private static function is_search_host( $host ) {
		return (bool) preg_match( '/(^|\.)google\.|(^|\.)bing\.|(^|\.)yahoo\.|(^|\.)duckduckgo\.|(^|\.)yandex\./', strtolower( (string) $host ) );
	}

	private static function is_social_source( $value ) {
		return (bool) preg_match( '/facebook|instagram|tiktok|linkedin|twitter|x\.com|youtube|pinterest|reddit/', strtolower( (string) $value ) );
	}

	private static function is_email_medium( $medium ) {
		return in_array( strtolower( (string) $medium ), array( 'email', 'e-mail', 'newsletter', 'mail' ), true );
	}

	private static function is_email_source( $source ) {
		return (bool) preg_match( '/mailchimp|klaviyo|brevo|sendgrid|newsletter|email/', strtolower( (string) $source ) );
	}

	private static function uuid() {
		return function_exists( 'wp_generate_uuid4' ) ? wp_generate_uuid4() : uniqid( 'traffic_', true );
	}
}
