<?php
// components/Assistant/Validator.php
namespace Components\Assistant;

class Validator
{
    public static function validate(array $step, array $input, array $context = []): array
    {
        $errors = [];
        $all = array_merge($context, $input);
        foreach ($step['items'] ?? [] as $it) {
            $id = $it['id'] ?? null;
            if (!$id) continue;
            $type = $it['type'] ?? 'text';
            $required = !empty($it['required']);
            $v = $input[$id] ?? null;
            $rules = is_array($it['validate'] ?? null) ? $it['validate'] : [];
            $ruleType = strtolower((string)($rules['type'] ?? ''));

            if ($required && ($v === null || $v === '' || (is_array($v) && !count($v)))) {
                $errors[$id] = \mh_lng('UI_VALIDATION_REQUIRED');
                continue;
            }
            if ($v === null || $v === '') continue;

            if ($type === 'text') {
                // Back-compat for text length
                $minLen = $rules['min_length'] ?? null;
                $maxLen = $rules['max_length'] ?? null;
                if ($minLen !== null || $maxLen !== null) {
                    $len = mb_strlen((string)$v);
                    if ($minLen && $len < (int)$minLen) { $errors[$id] = sprintf(\mh_lng('UI_VALIDATION_MIN_LENGTH'), $minLen); continue; }
                    if ($maxLen && $len > (int)$maxLen) { $errors[$id] = sprintf(\mh_lng('UI_VALIDATION_MAX_LENGTH'), $maxLen); continue; }
                }
                // Numeric integer support when validate.type=integer
                if ($ruleType === 'integer') {
                    if (!is_numeric($v) || (string)(int)$v !== (string)$v) {
                        $errors[$id] = \mh_lng('UI_VALIDATION_INTEGER');
                        continue;
                    }
                    $iv = (int)$v;
                    $min = isset($rules['min']) && $rules['min'] !== '' ? (int)$rules['min'] : null;
                    $max = isset($rules['max']) && $rules['max'] !== '' ? (int)$rules['max'] : null;
                    if ($min !== null && $iv < $min) { $errors[$id] = sprintf(\mh_lng('UI_VALIDATION_MIN_VALUE'), $min); continue; }
                    if ($max !== null && $iv > $max) { $errors[$id] = sprintf(\mh_lng('UI_VALIDATION_MAX_VALUE'), $max); continue; }
                }
            }

            if (in_array($type, ['single_choice','single_choice_rich','multi_choice'], true)) {
                $allowed = array_map(fn($o) => $o['id'], $it['options'] ?? []);
                $vals = $type === 'multi_choice' ? (array)$v : [$v];
                foreach ($vals as $val) if (!in_array($val, $allowed, true)) $errors[$id] = \mh_lng('UI_VALIDATION_INVALID_SELECTION');
            }

            // Cross-field comparison via validate.compare
            if (!empty($rules['compare'])) {
                $cmps = is_array($rules['compare']) && isset($rules['compare'][0]) ? $rules['compare'] : [$rules['compare']];
                foreach ($cmps as $cmp) {
                    if (!is_array($cmp)) continue;
                    $other = (string)($cmp['field'] ?? ''); if ($other === '') continue;
                    $op = strtolower((string)($cmp['op'] ?? 'gte'));
                    $offset = $cmp['offset'] ?? 0;
                    $msg = (string)($cmp['message'] ?? '');
                    if (!array_key_exists($other, $all)) continue; // other not available yet
                    $left = $v; $right = $all[$other];
                    $compared = false;
                    if (is_numeric($left) && (string)(int)$left === (string)$left && is_numeric($right) && (string)(int)$right === (string)$right) {
                        $left = (int)$left; $right = (int)$right + (int)$offset; $compared = true;
                    } else {
                        $lTs = self::parseDateToTs($left); $rTs = self::parseDateToTs($right);
                        if ($lTs !== null && $rTs !== null) { $days = is_numeric($offset) ? (int)$offset : 0; $left = $lTs; $right = $rTs + $days*86400; $compared = true; }
                    }
                    if ($compared) {
                        $ok = true;
                        switch ($op) {
                            case 'gt': case '>': $ok = ($left > $right); break;
                            case 'gte': case '>=': $ok = ($left >= $right); break;
                            case 'lt': case '<': $ok = ($left < $right); break;
                            case 'lte': case '<=': $ok = ($left <= $right); break;
                            case 'eq': case '==': $ok = ($left == $right); break;
                            case 'ne': case '!=': $ok = ($left != $right); break;
                            default: $ok = true;
                        }
                        if (!$ok) {
                            if ($msg === '') {
                                $offTxt = is_numeric($offset) ? (' + ' . (int)$offset) : '';
                                $msg = sprintf(\mh_lng('UI_VALIDATION_COMPARE'), $op, $other . $offTxt);
                            }
                            $errors[$id] = $msg;
                        }
                    }
                }
            }
        }
        return $errors;
    }

    private static function parseDateToTs($val): ?int
    {
        if ($val === null) return null;
        $s = trim((string)$val);
        if ($s === '') return null;
        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $s)) {
            $ts = strtotime($s . ' 00:00:00');
            if ($ts !== false) return $ts;
        }
        $t = strtotime($s);
        return $t !== false ? $t : null;
    }
}
