<?php

declare(strict_types=1);

namespace App\Application\LiveComponents\Stats;

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\Caching\VaryBy;
use App\Framework\LiveComponents\ComponentEventDispatcher;
use App\Framework\LiveComponents\Contracts\Cacheable;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;
use App\Framework\LiveComponents\ValueObjects\EventPayload;

/**
 * Statistics Component with Caching
 *
 * Demonstrates:
 * - Type-safe state management with StatsState Value Object
 * - Expensive data computation (simulated)
 * - Component-level caching with TTL
 * - Cache invalidation on demand
 * - Cache tags for grouped invalidation
 */
#[LiveComponent('stats')]
final readonly class StatsComponent implements LiveComponentContract, Cacheable
{
    public function __construct(
        public ComponentId $id,
        public StatsState $state
    ) {}

    public function getRenderData(): ComponentRenderData
    {
        // Simulate expensive computation
        $stats = $this->computeExpensiveStats();

        // Increment render count
        $newState = $this->state->incrementRenderCount();

        return new ComponentRenderData(
            templatePath: 'livecomponent-stats',
            data: [
                'stats' => $stats,
                'cache_enabled' => $newState->cacheEnabled,
                'last_update' => $newState->lastUpdate,
                'render_count' => $newState->renderCount,
            ]
        );
    }

    /**
     * Simulate expensive computation
     */
    private function computeExpensiveStats(): array
    {
        // Simulate expensive operation (database queries, API calls, etc.)
        usleep(500000); // 0.5 seconds delay

        return [
            'total_users' => rand(1000, 10000),
            'active_sessions' => rand(10, 100),
            'total_orders' => rand(100, 1000),
            'revenue' => rand(10000, 100000),
            'computed_at' => microtime(true),
        ];
    }

    /**
     * Refresh stats (invalidates cache)
     */
    public function refresh(?ComponentEventDispatcher $events = null): StatsState
    {
        // Cache will be invalidated by ComponentRegistry
        $events?->dispatch('stats:refreshed', EventPayload::fromArray([
            'component_id' => $this->id->toString(),
            'timestamp' => time(),
        ]));

        return $this->state->refresh();
    }

    /**
     * Toggle caching
     */
    public function toggleCache(): StatsState
    {
        return $this->state->toggleCache();
    }

    // Cacheable Interface Implementation

    /**
     * Get cache key - includes component ID and cache_enabled state
     */
    public function getCacheKey(): string
    {
        return $this->id->toString() . ':' . ($this->state->cacheEnabled ? 'enabled' : 'disabled');
    }

    /**
     * Cache for 30 seconds
     */
    public function getCacheTTL(): Duration
    {
        return Duration::fromSeconds(30);
    }

    /**
     * Only cache if caching is enabled
     */
    public function shouldCache(): bool
    {
        return $this->state->cacheEnabled;
    }

    /**
     * Cache tags for grouped invalidation
     */
    public function getCacheTags(): array
    {
        return [
            'stats',
            'dashboard-components',
        ];
    }

    /**
     * No cache variation - stats are global
     */
    public function getVaryBy(): ?VaryBy
    {
        return null;
    }

    /**
     * Enable stale-while-revalidate for better UX
     * Serve stale cache for up to 2 minutes while refreshing
     */
    public function getStaleWhileRevalidate(): ?Duration
    {
        return Duration::fromMinutes(2);
    }
}
