<?php

declare(strict_types=1);

namespace App\Framework\Http\Session;

use App\Framework\Validation\ValidationResult;

/**
 * A bag for managing validation errors associated with forms.
 *
 * This class provides methods to store, retrieve, check, and clear validation errors
 * for specific forms or fields within a session. Supports both single error messages
 * and multiple error messages per field.
 */
final readonly class ValidationErrorBag
{
    public function __construct(
        private Session $session
    ){
        #$this->session = $session;

        // Sicherstellen, dass Validierungsbereich existiert
        if (!$this->session->has(SessionKey::VALIDATION_ERRORS->value)) {
            $this->session->set(SessionKey::VALIDATION_ERRORS->value, []);
        }
    }

    /**
     * Fügt Validierungsfehler für ein Formular hinzu
     *
     * @param string $formId Formular-ID
     * @param array $errors Fehler-Array im Format ['field' => ['error1', 'error2']] oder ['field' => 'error']
     */
    public function add(string $formId, array $errors): void
    {
        $validationData = $this->session->get(SessionKey::VALIDATION_ERRORS->value, []);

        // Normalisiere das Fehler-Array, um sicherzustellen, dass alle Werte Arrays sind
        $normalizedErrors = [];
        foreach ($errors as $field => $fieldErrors) {
            if (is_array($fieldErrors)) {
                $normalizedErrors[$field] = $fieldErrors;
            } else {
                $normalizedErrors[$field] = [$fieldErrors];
            }
        }

        $validationData[$formId] = $normalizedErrors;
        $this->session->set(SessionKey::VALIDATION_ERRORS->value, $validationData);
    }

    /**
     * Fügt Validierungsfehler aus einem ValidationResult hinzu
     */
    public function addFromValidationResult(string $formId, ValidationResult $validationResult): void
    {
        $this->add($formId, $validationResult->getAll());
    }

    /**
     * Gibt alle Fehler für ein Formular zurück
     *
     * @param string $formId Formular-ID
     * @return array<string, string[]> Array von Fehlern gruppiert nach Feldern
     */
    public function get(string $formId): array
    {
        $validationData = $this->session->get(SessionKey::VALIDATION_ERRORS->value, []);
        return $validationData[$formId] ?? [];
    }

    /**
     * Prüft, ob Fehler für ein Formular oder Feld vorhanden sind
     */
    public function has(string $formId, ?string $field = null): bool
    {
        $validationData = $this->session->get(SessionKey::VALIDATION_ERRORS->value, []);

        if (!isset($validationData[$formId])) {
            return false;
        }

        if ($field === null) {
            return !empty($validationData[$formId]);
        }

        return isset($validationData[$formId][$field]) && !empty($validationData[$formId][$field]);
    }

    /**
     * Gibt alle Fehlermeldungen für ein bestimmtes Feld zurück
     *
     * @param string $formId Formular-ID
     * @param string $field Feldname
     * @return array<string> Array von Fehlermeldungen für das Feld
     */
    public function getFieldErrors(string $formId, string $field): array
    {
        $errors = $this->get($formId);
        return $errors[$field] ?? [];
    }

    /**
     * Gibt die erste Fehlermeldung für ein Feld zurück (Rückwärtskompatibilität)
     *
     * @param string $formId Formular-ID
     * @param string $field Feldname
     * @return string|null Erste Fehlermeldung oder null
     */
    public function getField(string $formId, string $field): ?string
    {
        $fieldErrors = $this->getFieldErrors($formId, $field);
        return $fieldErrors[0] ?? null;
    }

    /**
     * Gibt alle Fehlermeldungen für ein Feld als String zurück
     *
     * @param string $formId Formular-ID
     * @param string $field Feldname
     * @param string $separator Trennzeichen zwischen Fehlermeldungen
     * @return string Alle Fehlermeldungen als String
     */
    public function getFieldErrorsAsString(string $formId, string $field, string $separator = ', '): string
    {
        $fieldErrors = $this->getFieldErrors($formId, $field);
        return implode($separator, $fieldErrors);
    }

    /**
     * Gibt alle Fehlermeldungen als flache Liste zurück
     *
     * @param string $formId Formular-ID
     * @return array<string> Liste aller Fehlermeldungen
     */
    public function getAllErrorMessages(string $formId): array
    {
        $errors = $this->get($formId);
        $messages = [];

        foreach ($errors as $fieldErrors) {
            foreach ($fieldErrors as $error) {
                $messages[] = $error;
            }
        }

        return $messages;
    }

    /**
     * Fügt eine einzelne Fehlermeldung zu einem Feld hinzu
     */
    public function addFieldError(string $formId, string $field, string $error): void
    {
        $validationData = $this->session->get(SessionKey::VALIDATION_ERRORS->value, []);

        if (!isset($validationData[$formId])) {
            $validationData[$formId] = [];
        }

        if (!isset($validationData[$formId][$field])) {
            $validationData[$formId][$field] = [];
        }

        $validationData[$formId][$field][] = $error;
        $this->session->set(SessionKey::VALIDATION_ERRORS->value, $validationData);
    }

    /**
     * Löscht alle Fehler für ein Formular
     */
    public function clear(string $formId): void
    {
        $validationData = $this->session->get(SessionKey::VALIDATION_ERRORS->value, []);

        if (isset($validationData[$formId])) {
            unset($validationData[$formId]);
            $this->session->set(SessionKey::VALIDATION_ERRORS->value, $validationData);
        }
    }

    /**
     * Löscht Fehler für ein bestimmtes Feld
     */
    public function clearField(string $formId, string $field): void
    {
        $validationData = $this->session->get(SessionKey::VALIDATION_ERRORS->value, []);

        if (isset($validationData[$formId][$field])) {
            unset($validationData[$formId][$field]);
            $this->session->set(SessionKey::VALIDATION_ERRORS->value, $validationData);
        }
    }

    /**
     * Löscht alle Validierungsfehler
     */
    public function clearAll(): void
    {
        $this->session->set(SessionKey::VALIDATION_ERRORS->value, []);
    }

    public function __debugInfo(): array
    {
        return $this->session->get(SessionKey::VALIDATION_ERRORS->value, []);
    }
}
