<?php

declare(strict_types=1);

namespace App\Framework\Http\Session\ValueObjects;

use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Value Object representing a single validation error
 */
final readonly class ValidationError
{
    /**
     * @param string $field Field name
     * @param string $message Error message
     * @param Timestamp $timestamp When the error occurred
     * @param array<string, mixed> $metadata Additional metadata
     */
    public function __construct(
        public string $field,
        public string $message,
        public Timestamp $timestamp,
        public array $metadata = []
    ) {
    }

    /**
     * Create from array data
     * @param array<string, mixed> $data
     */
    public static function fromArray(array $data): self
    {
        return new self(
            field: $data['field'] ?? '',
            message: $data['message'] ?? '',
            timestamp: isset($data['timestamp'])
                ? Timestamp::fromFloat((float) $data['timestamp'])
                : Timestamp::fromFloat(microtime(true)),
            metadata: $data['metadata'] ?? []
        );
    }

    /**
     * Create new validation error
     */
    public static function create(string $field, string $message, array $metadata = []): self
    {
        return new self(
            field: $field,
            message: $message,
            timestamp: Timestamp::fromFloat(microtime(true)),
            metadata: $metadata
        );
    }

    /**
     * Convert to array
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        return [
            'field' => $this->field,
            'message' => $this->message,
            'timestamp' => $this->timestamp->toFloat(),
            'metadata' => $this->metadata,
        ];
    }

    /**
     * Get metadata value
     */
    public function getMetadata(string $key, mixed $default = null): mixed
    {
        return $this->metadata[$key] ?? $default;
    }

    /**
     * Check if error is older than given seconds
     */
    public function isOlderThan(int $seconds): bool
    {
        return $this->timestamp->toFloat() < (time() - $seconds);
    }

    /**
     * Get age in seconds
     */
    public function getAge(): int
    {
        return (int) (time() - $this->timestamp->toFloat());
    }

    /**
     * Create new instance with different message
     */
    public function withMessage(string $message): self
    {
        return new self(
            field: $this->field,
            message: $message,
            timestamp: $this->timestamp,
            metadata: $this->metadata
        );
    }

    /**
     * Create new instance with additional metadata
     */
    public function withMetadata(string $key, mixed $value): self
    {
        $metadata = $this->metadata;
        $metadata[$key] = $value;

        return new self(
            field: $this->field,
            message: $this->message,
            timestamp: $this->timestamp,
            metadata: $metadata
        );
    }
}
