<?php
namespace admin\Validation;

use admin\ViewModels\Forms\FormField;
use admin\ViewModels\Forms\FormFieldType;

/**
 * Walidator formularzy
 */
class FormValidator
{
    private array $errors = [];

    /**
     * Waliduje dane na podstawie definicji pól
     * 
     * @param array $data Dane z POST
     * @param array $fields Definicje pól (FormField[])
     * @param array|null $languages Języki (dla walidacji pól językowych)
     * @return array Tablica błędów (pusta jeśli OK)
     */
    public function validate(array $data, array $fields, ?array $languages = null): array
    {
        $this->errors = [];

        foreach ($fields as $field) {
            if ($field->type === FormFieldType::LANG_SECTION) {
                $this->validateLangSection($data, $field, $languages ?? []);
            } else {
                $this->validateField($data, $field);
            }
        }

        return $this->errors;
    }

    /**
     * Waliduje pojedyncze pole
     */
    private function validateField(array $data, FormField $field): void
    {
        $value = $data[$field->name] ?? null;

        // Walidacja wymagalności
        if ($field->required && $this->isEmpty($value)) {
            $this->errors[$field->name] = "Pole \"{$field->label}\" jest wymagane.";
            return;
        }

        // Jeśli pole puste i nie jest wymagane - pomijamy dalszą walidację
        if ($this->isEmpty($value)) {
            return;
        }

        // Walidacja typu
        switch ($field->type) {
            case FormFieldType::EMAIL:
                if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                    $this->errors[$field->name] = "Pole \"{$field->label}\" musi być poprawnym adresem e-mail.";
                }
                break;

            case FormFieldType::NUMBER:
                if (!is_numeric($value)) {
                    $this->errors[$field->name] = "Pole \"{$field->label}\" musi być liczbą.";
                }
                break;

            case FormFieldType::DATE:
                if (!$this->isValidDate($value)) {
                    $this->errors[$field->name] = "Pole \"{$field->label}\" musi być poprawną datą (YYYY-MM-DD).";
                }
                break;

            case FormFieldType::DATETIME:
                if (!$this->isValidDateTime($value)) {
                    $this->errors[$field->name] = "Pole \"{$field->label}\" musi być poprawną datą i czasem.";
                }
                break;
        }

        // Walidacja customowa (callback)
        if (isset($field->attributes['validate_callback']) && is_callable($field->attributes['validate_callback'])) {
            $result = call_user_func($field->attributes['validate_callback'], $value, $data);
            if ($result !== true) {
                $this->errors[$field->name] = is_string($result) ? $result : "Pole \"{$field->label}\" zawiera nieprawidłową wartość.";
            }
        }
    }

    /**
     * Waliduje sekcję językową
     */
    private function validateLangSection(array $data, FormField $section, array $languages): void
    {
        if ($section->langFields === null) {
            return;
        }

        foreach ($languages as $language) {
            if (!($language['status'] ?? false)) {
                continue;
            }

            $langId = $language['id'];

            foreach ($section->langFields as $field) {
                $fieldName = $field->name;
                $value = $data[$fieldName][$langId] ?? null;

                // Walidacja wymagalności
                if ($field->required && $this->isEmpty($value)) {
                    $errorKey = "{$section->name}_{$fieldName}";
                    $this->errors[$errorKey][$langId] = "Pole \"{$field->label}\" ({$language['name']}) jest wymagane.";
                    continue;
                }

                // Walidacja typu dla pól językowych
                if (!$this->isEmpty($value)) {
                    switch ($field->type) {
                        case FormFieldType::EMAIL:
                            if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                                $errorKey = "{$section->name}_{$fieldName}";
                                $this->errors[$errorKey][$langId] = "Pole \"{$field->label}\" ({$language['name']}) musi być poprawnym e-mailem.";
                            }
                            break;
                    }
                }
            }
        }
    }

    /**
     * Sprawdza czy wartość jest pusta
     */
    private function isEmpty($value): bool
    {
        return $value === null || $value === '' || (is_array($value) && empty($value));
    }

    /**
     * Sprawdza czy data jest poprawna (YYYY-MM-DD)
     */
    private function isValidDate(string $date): bool
    {
        $d = \DateTime::createFromFormat('Y-m-d', $date);
        return $d && $d->format('Y-m-d') === $date;
    }

    /**
     * Sprawdza czy data i czas są poprawne
     */
    private function isValidDateTime(string $datetime): bool
    {
        $d = \DateTime::createFromFormat('Y-m-d H:i:s', $datetime);
        if ($d && $d->format('Y-m-d H:i:s') === $datetime) {
            return true;
        }
        
        // Spróbuj bez sekund
        $d = \DateTime::createFromFormat('Y-m-d H:i', $datetime);
        return $d && $d->format('Y-m-d H:i') === $datetime;
    }

    /**
     * Sprawdza czy walidacja zakończyła się sukcesem
     */
    public function isValid(): bool
    {
        return empty($this->errors);
    }

    /**
     * Zwraca wszystkie błędy
     */
    public function getErrors(): array
    {
        return $this->errors;
    }

    /**
     * Zwraca pierwszy błąd
     */
    public function getFirstError(): ?string
    {
        if (empty($this->errors)) {
            return null;
        }

        $first = reset($this->errors);
        if (is_array($first)) {
            return reset($first);
        }
        return $first;
    }
}
