<?php
declare(strict_types=1);

namespace App\Framework\Validation\Exceptions;

use App\Framework\Exception\FrameworkException;
use App\Framework\Validation\ValidationResult;

final class ValidationException extends FrameworkException
{
    public readonly ValidationResult $validationResult;
    public readonly array $errors;
    public readonly string $field;

    /**
     * @param ValidationResult $validationResult Das Validierungsergebnis mit allen Fehlern
     * @param string|null $field Optionaler einzelner Feldname für Rückwärtskompatibilität
     */
    public function __construct(
        ValidationResult $validationResult,
        ?string $field = null
    ) {
        $this->validationResult = $validationResult;

        // Für Rückwärtskompatibilität: Wenn nur ein Feld angegeben wurde, verwende dessen Fehler
        if ($field !== null && $validationResult->getFieldErrors($field)) {
            $this->field = $field;
            $this->errors = $validationResult->getFieldErrors($field);
        } else {
            // Andernfalls verwende das erste Feld oder einen Standard
            $allErrors = $validationResult->getAll();
            $firstField = array_key_first($allErrors);
            $this->field = $firstField ?? 'unknown';
            $this->errors = $firstField ? $allErrors[$firstField] : [];
        }

        // Erstelle eine aussagekräftige Fehlernachricht aus allen Fehlern
        $message = $this->createErrorMessage();

        parent::__construct(message: $message);
    }

    /**
     * Erstellt eine strukturierte Fehlernachricht aus allen Validierungsfehlern
     */
    private function createErrorMessage(): string
    {
        $allErrors = $this->validationResult->getAll();

        if (empty($allErrors)) {
            return 'Unbekannter Validierungsfehler.';
        }

        $messages = [];
        foreach ($allErrors as $field => $fieldErrors) {
            $fieldMessage = $field . ': ' . implode(', ', $fieldErrors);
            $messages[] = $fieldMessage;
        }

        return implode('; ', $messages);
    }

    /**
     * Gibt alle Fehlermeldungen für ein bestimmtes Feld zurück
     *
     * @param string $field Feldname
     * @return array<string> Liste der Fehlermeldungen für das Feld
     */
    public function getFieldErrors(string $field): array
    {
        return $this->validationResult->getFieldErrors($field);
    }

    /**
     * Gibt alle Fehlermeldungen als Array zurück
     *
     * @return array<string, string[]> Alle Fehlermeldungen gruppiert nach Feldern
     */
    public function getAllErrors(): array
    {
        return $this->validationResult->getAll();
    }

    /**
     * Gibt alle Fehlermeldungen als flache Liste zurück
     *
     * @return array<string> Liste aller Fehlermeldungen
     */
    public function getAllErrorMessages(): array
    {
        return $this->validationResult->getAllErrorMessages();
    }

    /**
     * Prüft, ob ein bestimmtes Feld Fehler hat
     */
    public function hasFieldErrors(string $field): bool
    {
        return !empty($this->validationResult->getFieldErrors($field));
    }

    /**
     * Statische Factory-Methode für einfache Einzelfeld-Fehler (Rückwärtskompatibilität)
     *
     * @param array<string> $errors Liste der Fehlermeldungen
     * @param string $field Feldname
     * @return self
     */
    public static function forField(array $errors, string $field): self
    {
        $validationResult = new ValidationResult();
        $validationResult->addErrors($field, $errors);

        return new self($validationResult, $field);
    }
}
