<?php
/**
 * Outbound telemetry to api.maca.se (Maca Tjatt).
 *
 * @package Maca_Tjatt
 */

defined( 'ABSPATH' ) || exit;

define( 'MACA_TJATT_API_EVENTS_URL', 'https://api.maca.se/v1/tjatt/events.php' );
define( 'MACA_TJATT_API_PLUGIN_SLUG', 'maca-tjatt' );
define( 'MACA_TJATT_API_REPORTED_TRANSIENT', 'maca_tjatt_api_deactivated_reported' );

/**
 * Plugin version for API payloads.
 *
 * @return string
 */
function maca_tjatt_api_plugin_version() {
	if ( defined( 'MACA_TJATT_VERSION' ) ) {
		return MACA_TJATT_VERSION;
	}

	if ( ! function_exists( 'get_plugin_data' ) ) {
		require_once ABSPATH . 'wp-admin/includes/plugin.php';
	}

	$plugin_file = MACA_TJATT_PLUGIN_DIR . 'maca-tjatt.php';
	if ( ! is_readable( $plugin_file ) ) {
		return '';
	}

	$data = get_plugin_data( $plugin_file, false, false );

	return isset( $data['Version'] ) ? (string) $data['Version'] : '';
}

/**
 * Normalize a site URL for telemetry (aligned with api.maca.se).
 *
 * @param string $url Raw URL.
 * @return string
 */
function maca_tjatt_api_normalize_site_url( $url ) {
	$url = trim( (string) $url );
	if ( '' === $url ) {
		return '';
	}

	if ( ! preg_match( '#^https?://#i', $url ) ) {
		$url = 'https://' . ltrim( $url, '/' );
	}

	$parts = wp_parse_url( $url );
	if ( ! is_array( $parts ) || empty( $parts['host'] ) ) {
		return '';
	}

	$scheme = strtolower( (string) ( $parts['scheme'] ?? 'https' ) );
	if ( ! in_array( $scheme, array( 'http', 'https' ), true ) ) {
		return '';
	}

	$host = strtolower( (string) $parts['host'] );
	$path = (string) ( $parts['path'] ?? '/' );
	if ( '' === $path ) {
		$path = '/';
	} elseif ( '/' !== $path ) {
		$path = untrailingslashit( $path );
	}

	return $scheme . '://' . $host . $path;
}

/**
 * @param string $host Hostname or IP.
 * @return string
 */
function maca_tjatt_api_parse_host( $host ) {
	$host = strtolower( trim( (string) $host ) );
	if ( '' === $host ) {
		return '';
	}

	if ( strpos( $host, ':' ) !== false ) {
		$host = (string) strtok( $host, ':' );
	}

	return $host;
}

/**
 * @param string $host Hostname or IP.
 * @return bool
 */
function maca_tjatt_api_is_loopback_host( $host ) {
	$host = maca_tjatt_api_parse_host( $host );
	if ( '' === $host ) {
		return false;
	}

	if ( in_array( $host, array( 'localhost', '127.0.0.1', '::1', '0:0:0:0:0:0:0:1', '0.0.0.0' ), true ) ) {
		return true;
	}

	if ( filter_var( $host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
		return strpos( $host, '127.' ) === 0;
	}

	return false;
}

/**
 * @param string $host Hostname or IP.
 * @return bool
 */
function maca_tjatt_api_is_private_host( $host ) {
	$host = maca_tjatt_api_parse_host( $host );
	if ( '' === $host || maca_tjatt_api_is_loopback_host( $host ) ) {
		return false;
	}

	if ( filter_var( $host, FILTER_VALIDATE_IP ) ) {
		return filter_var( $host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) === false;
	}

	return (bool) preg_match( '/\.(local|test|localhost)$/', $host );
}

/**
 * @param string $host Hostname.
 * @return bool
 */
function maca_tjatt_api_is_valid_hostname( $host ) {
	$host = maca_tjatt_api_parse_host( $host );

	return '' !== $host
		&& strlen( $host ) <= 253
		&& (bool) preg_match( '/^[a-z0-9]([a-z0-9\-.]*[a-z0-9])?$/', $host );
}

/**
 * Detect request scheme, including common reverse-proxy headers.
 *
 * @return string http|https
 */
function maca_tjatt_api_detect_request_scheme() {
	if ( function_exists( 'is_ssl' ) && is_ssl() ) {
		return 'https';
	}

	if ( ! empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) {
		$forwarded = strtolower( trim( (string) $_SERVER['HTTP_X_FORWARDED_PROTO'] ) );
		if ( strpos( $forwarded, ',' ) !== false ) {
			$forwarded = trim( (string) strtok( $forwarded, ',' ) );
		}
		if ( 'https' === $forwarded ) {
			return 'https';
		}
	}

	if ( ! empty( $_SERVER['HTTP_X_FORWARDED_SSL'] ) && 'on' === strtolower( (string) $_SERVER['HTTP_X_FORWARDED_SSL'] ) ) {
		return 'https';
	}

	if ( ! empty( $_SERVER['HTTPS'] ) && 'off' !== strtolower( (string) $_SERVER['HTTPS'] ) ) {
		return 'https';
	}

	if ( ! empty( $_SERVER['SERVER_PORT'] ) && '443' === (string) $_SERVER['SERVER_PORT'] ) {
		return 'https';
	}

	return 'http';
}

/**
 * Collect candidate public site URLs from WordPress and the current request.
 *
 * @return array<int, string>
 */
function maca_tjatt_api_site_url_candidates() {
	$candidates = array();

	if ( function_exists( 'home_url' ) ) {
		$candidates[] = home_url( '/' );
	}
	if ( function_exists( 'site_url' ) ) {
		$candidates[] = site_url( '/' );
	}

	$home = get_option( 'home' );
	if ( is_string( $home ) && '' !== $home ) {
		$candidates[] = trailingslashit( $home );
	}

	$siteurl = get_option( 'siteurl' );
	if ( is_string( $siteurl ) && '' !== $siteurl ) {
		$candidates[] = trailingslashit( $siteurl );
	}

	$request_hosts = array();
	foreach ( array( 'HTTP_X_FORWARDED_HOST', 'HTTP_HOST', 'SERVER_NAME' ) as $server_key ) {
		if ( empty( $_SERVER[ $server_key ] ) ) {
			continue;
		}

		$raw = (string) $_SERVER[ $server_key ];
		foreach ( explode( ',', $raw ) as $part ) {
			$host = maca_tjatt_api_parse_host( $part );
			if ( '' !== $host ) {
				$request_hosts[] = $host;
			}
		}
	}

	$request_hosts = array_values( array_unique( $request_hosts ) );
	$scheme        = maca_tjatt_api_detect_request_scheme();

	foreach ( $request_hosts as $host ) {
		if ( ! maca_tjatt_api_is_valid_hostname( $host ) ) {
			continue;
		}

		$candidates[] = $scheme . '://' . $host . '/';
		if ( 'http' === $scheme ) {
			$candidates[] = 'https://' . $host . '/';
		}
	}

	/**
	 * Filter candidate site URLs before resolution.
	 *
	 * @param array<int, string> $candidates Candidate URLs.
	 */
	return apply_filters( 'maca_tjatt_api_site_url_candidates', $candidates );
}

/**
 * Score a candidate URL — higher is better.
 *
 * @param string $url Normalized URL.
 * @return int
 */
function maca_tjatt_api_score_site_url( $url ) {
	$parts = wp_parse_url( $url );
	if ( ! is_array( $parts ) || empty( $parts['host'] ) ) {
		return PHP_INT_MIN;
	}

	$host   = maca_tjatt_api_parse_host( (string) $parts['host'] );
	$scheme = strtolower( (string) ( $parts['scheme'] ?? 'http' ) );
	$score  = 0;

	if ( 'https' === $scheme ) {
		$score += 20;
	}

	if ( maca_tjatt_api_is_loopback_host( $host ) ) {
		$score -= 200;
	} elseif ( maca_tjatt_api_is_private_host( $host ) ) {
		$score -= 60;
	} else {
		$score += 100;
	}

	if ( strpos( $host, '.' ) !== false ) {
		$score += 10;
	}

	return $score;
}

/**
 * Resolve the best public site URL for telemetry.
 *
 * Prefers stored WordPress URLs, but falls back to the current request host
 * when home_url() points at loopback (common on some hosts/proxies).
 *
 * @return string
 */
function maca_tjatt_api_resolve_site_url() {
	$ranked = array();

	foreach ( maca_tjatt_api_site_url_candidates() as $candidate ) {
		$normalized = maca_tjatt_api_normalize_site_url( $candidate );
		if ( '' === $normalized ) {
			continue;
		}

		$score = maca_tjatt_api_score_site_url( $normalized );
		if ( ! isset( $ranked[ $normalized ] ) || $score > $ranked[ $normalized ] ) {
			$ranked[ $normalized ] = $score;
		}
	}

	if ( array() === $ranked ) {
		return function_exists( 'home_url' ) ? (string) home_url( '/' ) : '';
	}

	arsort( $ranked, SORT_NUMERIC );
	$resolved = (string) array_key_first( $ranked );

	/**
	 * Filter resolved site URL sent to api.maca.se.
	 *
	 * @param string             $resolved Resolved URL.
	 * @param array<string, int> $ranked   Scored candidates.
	 */
	return (string) apply_filters( 'maca_tjatt_api_site_url', $resolved, $ranked );
}

/**
 * Base payload shared by all events.
 *
 * @return array<string, string>
 */
function maca_tjatt_api_base_payload() {
	return array(
		'plugin'      => MACA_TJATT_API_PLUGIN_SLUG,
		'version'     => maca_tjatt_api_plugin_version(),
		'site_url'    => maca_tjatt_api_resolve_site_url(),
		'wp_version'  => get_bloginfo( 'version' ),
		'php_version' => PHP_VERSION,
		'locale'      => get_locale(),
	);
}

/**
 * Send an installation lifecycle event to api.maca.se.
 *
 * @param string               $event    activated|deactivated|uninstalled
 * @param array<string, mixed> $extra    Optional fields (reason, reason_label, details).
 * @param bool                 $blocking Wait for HTTP response.
 * @return bool True when the API accepted the request (2xx).
 */
function maca_tjatt_api_send_event( $event, array $extra = array(), $blocking = true ) {
	$allowed = array( 'activated', 'deactivated', 'uninstalled' );
	if ( ! in_array( $event, $allowed, true ) ) {
		return false;
	}

	$body = array_merge(
		maca_tjatt_api_base_payload(),
		array( 'event' => $event ),
		$extra
	);

	$response = wp_remote_post(
		MACA_TJATT_API_EVENTS_URL,
		array(
			'timeout'  => 5,
			'blocking' => $blocking,
			'headers'  => array(
				'Content-Type' => 'application/json; charset=utf-8',
				'Accept'       => 'application/json',
				'User-Agent'   => 'maca-tjatt/' . maca_tjatt_api_plugin_version(),
			),
			'body'     => wp_json_encode( $body ),
		)
	);

	if ( is_wp_error( $response ) ) {
		return false;
	}

	$code = (int) wp_remote_retrieve_response_code( $response );

	return $code >= 200 && $code < 300;
}

/**
 * Mark that deactivation was already reported (avoids duplicate with deactivate hook).
 *
 * @return void
 */
function maca_tjatt_api_mark_deactivated_reported() {
	set_transient( MACA_TJATT_API_REPORTED_TRANSIENT, 1, MINUTE_IN_SECONDS );
}

/**
 * Whether deactivation was reported in the last minute (e.g. via AJAX modal).
 *
 * @return bool
 */
function maca_tjatt_api_was_deactivated_reported() {
	return (bool) get_transient( MACA_TJATT_API_REPORTED_TRANSIENT );
}

/**
 * Report plugin activation to api.maca.se.
 *
 * Deferred to shutdown so URL helpers and proxy headers are fully available.
 *
 * @return void
 */
function maca_tjatt_api_on_activate() {
	static $scheduled = false;

	if ( $scheduled ) {
		return;
	}

	$scheduled = true;
	add_action( 'shutdown', 'maca_tjatt_api_send_activate_event', 1 );
}

/**
 * Send activation telemetry at end of request.
 *
 * @return void
 */
function maca_tjatt_api_send_activate_event() {
	static $sent = false;

	if ( $sent ) {
		return;
	}

	$sent = true;
	maca_tjatt_api_send_event( 'activated', array(), false );
}

/**
 * Report plugin deactivation to api.maca.se (bulk deactivate, etc.).
 *
 * @return void
 */
function maca_tjatt_api_on_deactivate() {
	if ( maca_tjatt_api_was_deactivated_reported() ) {
		return;
	}

	maca_tjatt_api_send_event( 'deactivated', array(), false );
}

/**
 * Report plugin uninstall to api.maca.se.
 *
 * @return void
 */
function maca_tjatt_api_on_uninstall() {
	maca_tjatt_api_send_event( 'uninstalled', array(), true );
}
