<?php

namespace SHServ\Helpers;

/**
 * Валидатор параметров action-скриптов по JSON-схеме.
 */
class ScriptParamsValidator {

	public static function validate(?Array $schema, Array $params): Array {
		if(!$schema) {
			return ["ok" => true, "errors" => [], "params" => $params];
		}

		$errors = [];
		$validated = [];

		foreach($schema as $name => $config) {
			$has_value = array_key_exists($name, $params);

			if(($config["required"] ?? false) && !$has_value) {
				$errors[] = ["field" => $name, "error" => "required"];
				continue;
			}

			if(!$has_value) {
				if(array_key_exists("default", $config)) {
					$validated[$name] = $config["default"];
				}
				continue;
			}

			$value = $params[$name];
			$type = $config["type"] ?? "text";
			$type_error = self::validate_type($name, $type, $value, $config);

			if($type_error) {
				$errors[] = $type_error;
				continue;
			}

			$validated[$name] = $value;
		}

		return [
			"ok"     => empty($errors),
			"errors" => $errors,
			"params" => $validated,
		];
	}

	protected static function validate_type(String $name, String $type, $value, Array $config): ?Array {
		switch($type) {
			case "text":
			case "textarea":
				if(!is_string($value)) {
					return ["field" => $name, "error" => "expected_string"];
				}
				return null;

			case "number":
				if(!self::is_numeric_value($value)) {
					return ["field" => $name, "error" => "expected_number"];
				}
				$num = (float) $value;
				if(isset($config["min"]) && $num < (float)$config["min"]) {
					return ["field" => $name, "error" => "min", "min" => $config["min"]];
				}
				if(isset($config["max"]) && $num > (float)$config["max"]) {
					return ["field" => $name, "error" => "max", "max" => $config["max"]];
				}
				return null;

			case "range":
				if(!self::is_numeric_value($value)) {
					return ["field" => $name, "error" => "expected_number"];
				}
				$num = (float) $value;
				if(isset($config["min"]) && $num < (float)$config["min"]) {
					return ["field" => $name, "error" => "min", "min" => $config["min"]];
				}
				if(isset($config["max"]) && $num > (float)$config["max"]) {
					return ["field" => $name, "error" => "max", "max" => $config["max"]];
				}
				return null;

			case "select":
				$options = array_keys($config["options"] ?? []);
				if(!in_array($value, $options, true)) {
					return ["field" => $name, "error" => "invalid_option"];
				}
				return null;

			case "toggle":
				if(!is_bool($value)) {
					return ["field" => $name, "error" => "expected_bool"];
				}
				return null;

			default:
				return null;
		}
	}

	protected static function is_numeric_value($value): Bool {
		return is_int($value) || is_float($value) || (is_string($value) && is_numeric($value));
	}
}
