<?php

namespace SHServ;

use \Fury\Modules\Router\Router;
use \Fury\Modules\ThinBuilder\ThinBuilder;
use \Fury\Modules\ErrorHandler\ErrorHandler;
use \SHServ\Factory\Factory;
use \SHServ\DevTools;

class App extends \Fury\Kernel\BaseApp{
	public $routes;
	public $router;
	public $events_handlers;
	public $error_handlers;
	public $thin_builder;
	public $console_flag;

	// CUSTOM
	public $utils;
	public $sessions;
	public $factory;
	public $devtools;

	public $control_scripts_instances = [];
	protected $required_control_scripts_instance;

	public function __construct() {
		parent::__construct();

		global $argv;
		$this -> console_flag = isset($argv) ? true : false;
		$this -> app_init();

	}

	public function app_init(): void {
		if(!$this -> console_flag) {
			$this -> error_handlers = new ErrorHandler();
		}
		
		\Fury\Modules\Template\Template::set_driver(new \Fury\Drivers\TemplateDriver());

		$this -> router_json_to_post_emulate();

		$this -> devtools = new DevTools();
		$this -> router = new Router();
		$this -> routes = new Routes($this -> router);
		$this -> thin_builder = new ThinBuilder(FCONF['db'], new \Fury\Drivers\ThinBuilderDriver(bootstrap()));
		$this -> control_scripts_init();
		$this -> events_handlers = new EventsHandlers();
		$this -> events_handlers -> handlers();

		// CUSTOM
		$this -> utils = new Utils();
		$this -> sessions = new Sessions();
		$this -> factory = new Factory();
	}

	/**
	 * Проверить авторизацию и rate limit для API запроса.
	 *
	 * @return array|null Null если запрос проходит, массив ['code' => int, 'body' => array] если нужно отклонить.
	 */
	public function check_api_auth(): ?array {
		$uri = $_SERVER['REQUEST_URI'] ?? '';
		if (strpos($uri, '/api/v1/') !== 0) {
			return null;
		}

		// Rate limiting: 60 req/min per IP
		$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
		$rate_limiter = new \SHServ\Tools\RateLimiter(60, 60);
		if (!$rate_limiter -> check($ip)) {
			return [
				'code' => 429,
				'body' => [
					'status' => false,
					'error_alias' => 'rate_limit_exceeded',
					'msg' => 'Too many requests'
				]
			];
		}

		$token = null;

		$auth_header = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '';
		if (strpos($auth_header, 'Bearer ') === 0) {
			$token = substr($auth_header, 7);
		}

		if (!$token && isset($_COOKIE['auth_token'])) {
			$token = $_COOKIE['auth_token'];
		}

		if (!$token || !app() -> sessions -> get_session_by_token($token)) {
			return [
				'code' => 401,
				'body' => [
					'status' => false,
					'error_alias' => 'unauthorized',
					'msg' => 'Authentication required'
				]
			];
		}

		return null;
	}

	public function api_auth_guard(): void {
		$response = $this -> check_api_auth();
		if ($response === null) {
			return;
		}

		header('Content-Type: application/json');
		http_response_code($response['code']);
		echo json_encode($response['body']);
		exit;
	}

	public function root_folder(): String {
		return dirname(__DIR__, 2);
	}

	protected function router_json_to_post_emulate(): void {
		$content_type = $_SERVER['CONTENT_TYPE'] ?? '';

		if (stripos($content_type, 'application/json') === false) {
	    return;
		}

		$raw_body = file_get_contents('php://input');
		$json_data = json_decode($raw_body, true);

		if (json_last_error() !== JSON_ERROR_NONE) {
	    return;
		}

		foreach($json_data as $param_name => $param_val) {
			$_POST[$param_name] = $param_val;
		}
	}

	public function control_scripts_init(): void {
		\SHServ\Middleware\ControlScripts::flush_statics();

		$this -> required_control_scripts_instance = new \SHServ\RequiredControlScriptsScope();

		$scopes_dir = __DIR__ . "/../ControlScripts/Scopes/";
		$scripts_dir = scandir($scopes_dir);
		$scripts = array_filter($scripts_dir, function($item) use ($scopes_dir) {
			return !is_dir($scopes_dir . $item) and (pathinfo($item))["extension"] == "php";
		});

		foreach($scripts as $script_name) {
			$script_name = basename($script_name, ".php");
			$full_script_name = "\\ControlScripts\\Scopes\\{$script_name}";

			$script = new $full_script_name();
			$this -> control_scripts_instances[$script_name] = $script;
		}
	}
}

if (!defined('PHPUNIT_TEST') || !PHPUNIT_TEST) {
	new App();
}