<?php

namespace SHServ\Middleware;

/**
 * RequestLogger — логирует начало и конец каждого HTTP-запроса (или CLI-команды).
 *
 * Регистрируется через события Fury:
 *   - Bootstrap.app_starting   → начало запроса
 *   - CallControl.leading_call → имя вызываемого action
 *   - Bootstrap.app_finished   → конец запроса
 *
 * Fallback через register_shutdown_function на случай exit/die.
 */
class RequestLogger {
	protected static ?float $start_time = null;
	protected static bool $completed = false;
	protected static ?string $action_name = null;
	protected static bool $initialized = false;

	public static function reset(): void {
		self::$initialized = false;
		self::$start_time = null;
		self::$completed = false;
		self::$action_name = null;
	}

	public function __construct() {
		if (self::$initialized) {
			return;
		}
		self::$initialized = true;
		self::$start_time = null;
		self::$completed = false;
		self::$action_name = null;

		global $argv;
		$is_cli = isset($argv);

		if ($is_cli) {
			$this -> register_cli_handlers($argv);
		} else {
			$this -> register_http_handlers();
		}
	}

	// ============================================================
	// HTTP
	// ============================================================

	protected function register_http_handlers(): void {
		self::$start_time = microtime(true);
		self::$completed = false;

		$uri = $_SERVER['REQUEST_URI'] ?? '';
		if (strpos($uri, '?') !== false) {
			list($path, $query) = explode('?', $uri, 2);
		} else {
			$path = $uri;
			$query = '';
		}

		logging() -> info('php:RequestLogger', 'Request started', [
			'method'         => $_SERVER['REQUEST_METHOD'] ?? 'UNKNOWN',
			'path'           => $path,
			'query'          => $query,
			'ip'             => $_SERVER['REMOTE_ADDR'] ?? '',
			'ua'             => $_SERVER['HTTP_USER_AGENT'] ?? '',
			'content_length' => $_SERVER['CONTENT_LENGTH'] ?? 0,
			'content_type'   => $_SERVER['CONTENT_TYPE'] ?? '',
		]);

		events() -> handler('kernel:CallControl.leading_call', function(Array $params) {
			$action = is_string($params['action'] ?? null)
				? $params['action']
				: 'anon';
			self::$action_name = $action;

			logging() -> debug('php:RequestLogger', 'Action dispatch', [
				'action' => $action,
				'type'   => $params['type'] ?? '',
			]);
		});

		events() -> handler('kernel:Bootstrap.app_finished', function(Array $params) {
			self::$completed = true;
			$this -> log_request_end();
		});

		register_shutdown_function(function() {
			if (self::$completed) {
				return;
			}
			logging() -> warn('php:RequestLogger', 'Request aborted or exited before app_finished', [
				'duration_ms' => self::$start_time !== null
					? round((microtime(true) - self::$start_time) * 1000, 3)
					: null,
				'aborted'     => true,
			]);
		});
	}

	protected function log_request_end(): void {
		$duration = self::$start_time !== null
			? round((microtime(true) - self::$start_time) * 1000, 3)
			: null;

		$code = http_response_code();
		if ($code === 0 || $code === false) {
			$code = 200;
		}

		logging() -> info('php:RequestLogger', 'Request completed', [
			'duration_ms'    => $duration,
			'memory_peak_mb' => round(memory_get_peak_usage(true) / 1024 / 1024, 2),
			'status_code'    => $code,
			'action'         => self::$action_name,
		]);
	}

	// ============================================================
	// CLI
	// ============================================================

	protected function register_cli_handlers(array $argv): void {
		self::$start_time = microtime(true);

		logging() -> info('php:RequestLogger', 'Console command started', [
			'argv' => $argv,
		]);

		register_shutdown_function(function() use ($argv) {
			$duration = self::$start_time !== null
				? round((microtime(true) - self::$start_time) * 1000, 3)
				: null;

			logging() -> info('php:RequestLogger', 'Console command finished', [
				'argv'        => $argv,
				'duration_ms' => $duration,
			]);
		});
	}
}
