<?php
declare(strict_types=1);

namespace Celena\Core\Security;

/**
 * Типизация и санитайзинг пользовательского ввода.
 * НЕ предназначен для экранирования вывода — для этого e().
 */
final class Filter
{
    public static function int(mixed $value, int $default = 0): int
    {
        return (int) filter_var($value, FILTER_VALIDATE_INT, ['options' => ['default' => $default]]);
    }

    public static function string(mixed $value, int $maxLength = 65535): string
    {
        $s = (string) $value;
        // вырезаем нулевые байты и управляющие символы кроме \t\r\n
        $s = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/u', '', $s) ?? '';
        if (mb_strlen($s, 'UTF-8') > $maxLength) {
            $s = mb_substr($s, 0, $maxLength, 'UTF-8');
        }
        return trim($s);
    }

    public static function email(mixed $value): ?string
    {
        $v = filter_var(trim((string) $value), FILTER_VALIDATE_EMAIL);
        return $v === false ? null : (string) $v;
    }

    public static function url(mixed $value): ?string
    {
        $v = filter_var(trim((string) $value), FILTER_VALIDATE_URL);
        return $v === false ? null : (string) $v;
    }

    /** Мягкая очистка slug для поиска в БД: без транслитерации, сохраняет кириллицу. */
    public static function urlSlug(mixed $value, int $maxLength = 200): string
    {
        $s = mb_strtolower((string) $value, 'UTF-8');
        $s = preg_replace('/[^\p{L}\p{N}]+/u', '-', $s) ?? '';
        $s = trim($s, '-');
        if (mb_strlen($s, 'UTF-8') > $maxLength) {
            $s = mb_substr($s, 0, $maxLength, 'UTF-8');
        }
        return $s;
    }

    public static function slug(mixed $value, int $maxLength = 200): string
    {
        $s = mb_strtolower((string) $value, 'UTF-8');
        $s = self::transliterate($s);
        $s = preg_replace('/[^a-z0-9]+/u', '-', $s) ?? '';
        $s = trim($s, '-');
        if ($s === '') {
            // если после транслита пусто — fallback на hex из хеша
            $s = 'n-' . substr(sha1((string) $value), 0, 10);
        }
        if (mb_strlen($s, 'UTF-8') > $maxLength) {
            $s = mb_substr($s, 0, $maxLength, 'UTF-8');
        }
        return $s;
    }

    /** Кириллица → латиница (ГОСТ-совместимая упрощённая таблица). */
    private static function transliterate(string $s): string
    {
        static $map = [
            'а'=>'a','б'=>'b','в'=>'v','г'=>'g','д'=>'d','е'=>'e','ё'=>'e',
            'ж'=>'zh','з'=>'z','и'=>'i','й'=>'y','к'=>'k','л'=>'l','м'=>'m',
            'н'=>'n','о'=>'o','п'=>'p','р'=>'r','с'=>'s','т'=>'t','у'=>'u',
            'ф'=>'f','х'=>'kh','ц'=>'ts','ч'=>'ch','ш'=>'sh','щ'=>'sch',
            'ъ'=>'','ы'=>'y','ь'=>'','э'=>'e','ю'=>'yu','я'=>'ya',
            'ә'=>'a','і'=>'i','ң'=>'n','ғ'=>'g','ү'=>'u','ұ'=>'u','қ'=>'k','ө'=>'o','һ'=>'h',
        ];
        return strtr($s, $map);
    }

    public static function bool(mixed $value): bool
    {
        if (is_bool($value)) {
            return $value;
        }
        $s = strtolower((string) $value);
        return in_array($s, ['1', 'true', 'on', 'yes', 'y'], true);
    }

    public static function in(mixed $value, array $allowed, mixed $default = null): mixed
    {
        return in_array($value, $allowed, true) ? $value : $default;
    }

    public static function path(mixed $value): string
    {
        // защита от directory traversal
        $s = (string) $value;
        $s = str_replace(['..', "\0"], '', $s);
        return ltrim(preg_replace('#/+#', '/', $s) ?? '', '/');
    }
}
