<?php

declare(strict_types=1);

namespace App\Framework\Http\Session\ValueObjects;

use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Value Object representing a single flash message
 */
final readonly class FlashMessage
{
    /**
     * @param FlashMessageType $type Message type
     * @param string $message Message content
     * @param Timestamp $timestamp When the message was created
     * @param array<string, mixed> $metadata Additional metadata
     */
    public function __construct(
        public FlashMessageType $type,
        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
    {
        $type = isset($data['type'])
            ? FlashMessageType::tryFrom($data['type']) ?? FlashMessageType::INFO
            : FlashMessageType::INFO;

        return new self(
            type: $type,
            message: $data['message'] ?? '',
            timestamp: isset($data['timestamp'])
                ? Timestamp::fromFloat((float) $data['timestamp'])
                : Timestamp::now(),
            metadata: $data['metadata'] ?? []
        );
    }

    /**
     * Create success message
     */
    public static function success(string $message, array $metadata = []): self
    {
        return new self(FlashMessageType::SUCCESS, $message, Timestamp::fromFloat(microtime(true)), $metadata);
    }

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

    /**
     * Create warning message
     */
    public static function warning(string $message, array $metadata = []): self
    {
        return new self(FlashMessageType::WARNING, $message, Timestamp::fromFloat(microtime(true)), $metadata);
    }

    /**
     * Create info message
     */
    public static function info(string $message, array $metadata = []): self
    {
        return new self(FlashMessageType::INFO, $message, Timestamp::fromFloat(microtime(true)), $metadata);
    }

    /**
     * Convert to array
     * @return array<string, mixed>
     */
    public function toArray(): array
    {
        return [
            'type' => $this->type->value,
            '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 message 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());
    }

    /**
     * Check if message is of specific type
     */
    public function isType(FlashMessageType $type): bool
    {
        return $this->type === $type;
    }

    /**
     * Check if message is success type
     */
    public function isSuccess(): bool
    {
        return $this->type === FlashMessageType::SUCCESS;
    }

    /**
     * Check if message is error type
     */
    public function isError(): bool
    {
        return $this->type === FlashMessageType::ERROR;
    }

    /**
     * Check if message is warning type
     */
    public function isWarning(): bool
    {
        return $this->type === FlashMessageType::WARNING;
    }

    /**
     * Check if message is info type
     */
    public function isInfo(): bool
    {
        return $this->type === FlashMessageType::INFO;
    }

    /**
     * Get CSS class for styling
     */
    public function getCssClass(): string
    {
        return $this->type->getCssClass();
    }

    /**
     * Get icon for the message
     */
    public function getIcon(): string
    {
        return $this->type->getIcon();
    }

    /**
     * Get human-readable label
     */
    public function getLabel(): string
    {
        return $this->type->getLabel();
    }

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

    /**
     * Create new instance with different message
     */
    public function withMessage(string $message): self
    {
        return new self(
            type: $this->type,
            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(
            type: $this->type,
            message: $this->message,
            timestamp: $this->timestamp,
            metadata: $metadata
        );
    }
}
