<?php
namespace PageVICO\Sessions;

defined( 'ABSPATH' ) || exit;

use PageVICO\Geo\GeoService;

class SessionManager {
	public static function init() {
		// No need for template_redirect hook anymore as we use trackers.js
	}

	public static function updateSessionLastSeen( $session_id, $data = array() ) {
		global $wpdb;
		$table = PageVICO_TABLE_SESSIONS;

		// First check if session exists and is active
		$existing_session = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT session_id, is_active FROM {$table} WHERE session_id = %s",
				$session_id
			)
		);

		// Only update if session exists and is active
		if ($existing_session && $existing_session->is_active) {
			$update_data = array(
				'last_seen' => current_time('mysql')
			);

			// Add screen dimensions if provided
			if (isset($data['screen_width'])) {
				$update_data['screen_width'] = intval($data['screen_width']);
			}
			if (isset($data['screen_height'])) {
				$update_data['screen_height'] = intval($data['screen_height']);
			}

			$wpdb->update(
				$table,
				$update_data,
				array( 'session_id' => $session_id ),
				array( '%s' ),
				array( '%s' )
			);

			if ($wpdb->last_error) {
				// Error updating session silently
			}
			return true;
		}
		
		// If session doesn't exist or is inactive, return false
		return false;
	}

	public static function sessionExists( $session_id ) {
		global $wpdb;
		$table = PageVICO_TABLE_SESSIONS;
	
		// Manually inject the table name; prepare() should only be used for values
		$sql = $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE session_id = %s",
			$session_id
		);
	
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Safe query with validated table name and prepared value
		$count = (int) $wpdb->get_var( $sql );
	
		return $count > 0;
	}

	/**
	 * Check if the session is active based on last_seen timestamp
	 * 
	 * @param string $session_id The session ID to check
	 * @return bool Whether the session is still active
	 */
	public static function isSessionActive( $session_id ) {
		global $wpdb;
		$table = PageVICO_TABLE_SESSIONS;
		
		// Get the timeout minutes from settings (defaults to 30 if not set)
		$timeout_minutes = get_option('session_timeout_minutes', 30);
		
		$threshold_time = date( 'Y-m-d H:i:s', current_time('timestamp') - ($timeout_minutes * 60) );
		
		// Check if the session exists and has been active within the timeout period
		$sql = $wpdb->prepare(
			"SELECT COUNT(*) FROM {$table} WHERE session_id = %s AND last_seen >= %s",
			$session_id,
			$threshold_time
		);
		
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Safe query with validated table name and prepared value
		$count = (int) $wpdb->get_var( $sql );
		
		return $count > 0;
	}

	/**
	 * Expire inactive sessions by marking them as ended
	 * This is called periodically to clean up sessions
	 * 
	 * @param int $timeout_minutes Minutes after which a session is considered expired
	 * @return int Number of sessions marked as expired
	 */
	public static function expireInactiveSessions() {
		global $wpdb;
		$table = PageVICO_TABLE_SESSIONS;

		$timeout_minutes = get_option('session_timeout_minutes', 30);

		// Get the timeout minutes from settings (defaults to 30 if not set)
		$threshold_time = current_time( 'mysql', false ); // false = local time
		$threshold_timestamp = strtotime( $threshold_time ) - ( $timeout_minutes * 60 );
		$threshold_time = date( 'Y-m-d H:i:s', $threshold_timestamp );
		
		// Update sessions that haven't been seen in the timeout period
		$sql = $wpdb->prepare(
			"UPDATE {$table} 
			SET is_active = 0 
			WHERE last_seen < %s 
			AND is_active = 1",
			$threshold_time
		);

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Safe update, no caching needed for writes
		$wpdb->query( $sql );
		
		return $wpdb->rows_affected;
	}

	public static function createSession( $session_id, $data = array() ) {
		global $wpdb;

		try {
			$ip      = self::getClientIP();
			$ip_hash = hash( 'sha256', $ip );
			$ua      = sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ?? '' ) );
			$device  = self::getDevice( $ua );
			$browser = self::getBrowser( $ua );
			$os      = self::getOS( $ua );
			$utm     = self::getUTM();

			$location_data = \PageVICO\Geo\GeoService::getLocationDataByIP( $ip );

			// Get screen dimensions from request if available
			$screen_w = isset($data['screen_width']) ? intval($data['screen_width']) : 0;
			$screen_h = isset($data['screen_height']) ? intval($data['screen_height']) : 0;

			// Check if session exists
			$existing_session = $wpdb->get_row(
				$wpdb->prepare(
					"SELECT session_id, is_active FROM " . PageVICO_TABLE_SESSIONS . " WHERE session_id = %s",
					$session_id
				)
			);

			// If session exists and is active, update it
			if ($existing_session) {
				$wpdb->update(
					PageVICO_TABLE_SESSIONS,
					array(
						'last_seen'     => current_time('mysql'),
						'screen_width'  => $screen_w,
						'screen_height' => $screen_h,
						'utm_source'    => $utm['source'],
						'utm_medium'    => $utm['medium'],
						'utm_campaign'  => $utm['campaign'],
						'utm_term'      => $utm['term'],
						'utm_content'   => $utm['content'],
						'is_active'     => 1
					),
					array('session_id' => $session_id),
					array('%s', '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%d'),
					array('%s')
				);
				if ($wpdb->last_error) {
				}
				return true;
			}

			// If session doesn't exist or is inactive, create new session
			$result = $wpdb->insert(
				PageVICO_TABLE_SESSIONS,
				array(
					'session_id'    => $session_id,
					'ip_hash'       => $ip_hash,
					'country'       => $location_data['country'],
					'region'        => $location_data['region'],
					'city'          => $location_data['city'],
					'user_agent'    => $ua,
					'device_type'   => $device,
					'browser'       => $browser,
					'os'            => $os,
					'screen_width'  => $screen_w,
					'screen_height' => $screen_h,
					'utm_source'    => $utm['source'],
					'utm_medium'    => $utm['medium'],
					'utm_campaign'  => $utm['campaign'],
					'utm_term'      => $utm['term'],
					'utm_content'   => $utm['content'],
					'first_seen'    => current_time('mysql'),
					'last_seen'     => current_time('mysql'),
					'is_bot'        => 0,
					'is_active'     => 1,
				),
				array(
					'%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%d', '%d'
				)
			);

			if ($result === false) {
				return false;
			}

			return true;

		} catch ( \Exception $e ) {
			return false;
		}
	}

	/**
     * Get client IP address
     */
    public static function getClientIP() {
        // Get the raw IP address from server variables
		$ip = isset($_SERVER['HTTP_CLIENT_IP']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_CLIENT_IP'])) : null;
        $ip = $ip ?: (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR'])) : null);
        $ip = $ip ?: (isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '0.0.0.0');

        // If multiple IPs are present, take the first one
        if (strpos($ip, ',') !== false) {
            $ips = explode(',', $ip);
            $ip  = trim($ips[0]);
        }

        // Sanitize the IP
        $ip = sanitize_text_field($ip);

        // Final validation
        return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '0.0.0.0';
    }

	public static function getDevice( $ua ) {
		if ( preg_match( '/mobile/i', $ua ) ) {
			return 'mobile';
		}
		if ( preg_match( '/tablet/i', $ua ) ) {
			return 'tablet';
		}
		return 'desktop';
	}

	public static function getBrowser( $ua ) {
		if ( strpos( $ua, 'Firefox' ) !== false ) {
			return 'Firefox';
		}
		if ( strpos( $ua, 'Chrome' ) !== false ) {
			return 'Chrome';
		}
		if ( strpos( $ua, 'Safari' ) !== false ) {
			return 'Safari';
		}
		if ( strpos( $ua, 'Edge' ) !== false ) {
			return 'Edge';
		}
		if ( strpos( $ua, 'MSIE' ) !== false || strpos( $ua, 'Trident/' ) !== false ) {
			return 'Internet Explorer';
		}
		return 'Other';
	}

	public static function getOS( $ua ) {
		if ( strpos( $ua, 'Windows' ) !== false ) {
			return 'Windows';
		}
		if ( strpos( $ua, 'Macintosh' ) !== false ) {
			return 'macOS';
		}
		if ( strpos( $ua, 'Linux' ) !== false ) {
			return 'Linux';
		}
		if ( strpos( $ua, 'Android' ) !== false ) {
			return 'Android';
		}
		if ( strpos( $ua, 'iPhone' ) !== false || strpos( $ua, 'iPad' ) !== false ) {
			return 'iOS';
		}
		return 'Other';
	}

	public static function getUTM() {
		$utm = array(
			'source'   => null,
			'medium'   => null,
			'campaign' => null,
			'term'     => null,
			'content'  => null
		);

		// Check URL parameters first
		foreach ($utm as $key => $value) {
			$param = 'utm_' . $key;
			if (isset($_GET[$param])) {
				$utm[$key] = sanitize_text_field(wp_unslash($_GET[$param]));
			}
		}

		// If no UTM parameters in URL, check referrer
		if (empty(array_filter($utm))) {
			$referrer = wp_get_raw_referer();
			if ($referrer) {
				$parsed_url = parse_url($referrer);
				if (isset($parsed_url['query'])) {
					parse_str($parsed_url['query'], $query_params);
					foreach ($utm as $key => $value) {
						$param = 'utm_' . $key;
						if (isset($query_params[$param])) {
							$utm[$key] = sanitize_text_field($query_params[$param]);
						}
					}
				}
			}
		}

		return $utm;
	}
}
