<?php

declare(strict_types=1);

namespace App\Application\LiveComponents\InfiniteScroll;

use App\Application\LiveComponents\Services\ScrollDataProvider;
use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\DataProviderResolver;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;

/**
 * InfiniteScrollComponent - Lazy loading content with infinite scroll
 *
 * Demonstrates:
 * - Type-safe state management with InfiniteScrollState Value Object
 * - Infinite scroll pagination (load more on scroll)
 * - Configurable page size and total items
 * - Loading states and end-of-content detection
 * - Performance metrics (items loaded, load time)
 * - Virtual scrolling ready architecture
 * - Uses ScrollDataProvider for flexible data sources (Demo, Database, API, etc.)
 */
#[LiveComponent('infinite-scroll')]
final readonly class InfiniteScrollComponent implements LiveComponentContract
{
    /**
     * Create Infinite Scroll with explicit, type-safe parameters
     */
    public function __construct(
        public ComponentId $id,
        public InfiniteScrollState $state,
        private readonly DataProviderResolver $dataProviderResolver
    ) {
    }

    public function getRenderData(): ComponentRenderData
    {
        return new ComponentRenderData(
            templatePath: 'livecomponent-infinite-scroll',
            data: [
                // Raw data
                'items' => $this->prepareItemsForDisplay($this->state->items),
                'current_page' => $this->state->currentPage,
                'page_size' => $this->state->pageSize,
                'total_items' => $this->state->totalItems,
                'has_more' => $this->state->hasMore,
                'loading' => $this->state->loading,
                'items_loaded' => $this->state->itemsLoaded,
                'execution_time_ms' => $this->state->executionTimeMs,
                'last_load_count' => $this->state->lastLoadCount,

                // Display-specific properties
                'hasItems' => $this->state->hasItems(),
                'showLoadMore' => $this->state->hasMore && ! $this->state->loading,
                'showEndMessage' => ! $this->state->hasMore && $this->state->hasItems(),
                'showLoadingSpinner' => $this->state->loading,
                'loadMoreButtonText' => $this->state->loading ? 'Lädt...' : 'Mehr laden',
                'loadMoreButtonClass' => $this->state->loading ? 'btn-loading' : 'btn-primary',
                'progressPercentage' => $this->state->getProgressPercentage(),
                'progressText' => $this->state->getProgressText(),
                'remainingItems' => $this->state->getRemainingItems(),
                'remainingText' => $this->state->getRemainingText(),
                'pageSizeOptions' => $this->getPageSizeOptions($this->state->pageSize),
                'endMessage' => 'Alle Einträge geladen',
                'emptyStateMessage' => 'Keine Einträge vorhanden',
                'showPerformanceMetrics' => $this->state->executionTimeMs > 0,
            ]
        );
    }

    // Action methods - Type-safe parameters

    #[Action(description: 'Load more items')]
    public function loadMore(): InfiniteScrollState
    {
        $startTime = microtime(true);

        // Calculate next page
        $nextPage = $this->state->currentPage + 1;

        // Load next batch from provider
        $newItemsVOs = $this->dataProvider->getItems($nextPage, $this->state->pageSize);
        $totalItems = $this->dataProvider->getTotalCount();
        $hasMore = $this->dataProvider->hasMore($nextPage, $this->state->pageSize);

        // Convert VOs to arrays
        $newItems = array_map(fn ($item) => $item->toArray(), $newItemsVOs);

        $executionTime = round((microtime(true) - $startTime) * 1000, 2);

        // Update state with new items
        return $this->state->withLoadedItems($newItems, $totalItems, $hasMore, $executionTime);
    }

    #[Action(description: 'Reset to first page')]
    public function reset(): InfiniteScrollState
    {
        // Load first page from provider
        $itemsVOs = $this->dataProvider->getItems(1, $this->state->pageSize);
        $initialItems = array_map(fn ($item) => $item->toArray(), $itemsVOs);
        $totalItems = $this->dataProvider->getTotalCount();
        $hasMore = $this->dataProvider->hasMore(1, $this->state->pageSize);

        return $this->state->reset($initialItems, $totalItems, $hasMore);
    }

    #[Action(description: 'Change page size')]
    public function changePageSize(int $pageSize): InfiniteScrollState
    {
        // Reset to first page with new page size from provider
        $itemsVOs = $this->dataProvider->getItems(1, $pageSize);
        $initialItems = array_map(fn ($item) => $item->toArray(), $itemsVOs);
        $totalItems = $this->dataProvider->getTotalCount();
        $hasMore = $this->dataProvider->hasMore(1, $pageSize);

        return $this->state->withPageSize($pageSize, $initialItems, $totalItems, $hasMore);
    }

    // Helper methods

    private function prepareItemsForDisplay(array $items): array
    {
        return array_map(function ($item, $index) {
            // Items are already arrays from toArray(), add display properties
            return array_merge($item, [
                'displayIndex' => $index + 1,
                'categoryClass' => 'category-' . strtolower(str_replace(' ', '-', $item['category'] ?? 'default')),
                'formattedDate' => $this->formatDate($item['date'] ?? ''),
                'formattedLikes' => $this->formatNumber($item['likes'] ?? 0),
                'formattedViews' => $this->formatNumber($item['views'] ?? 0),
                // Use ScrollItem logic through array data
                'isPopular' => ($item['views'] ?? 0) > 5000,
                'isTrending' => ($item['likes'] ?? 0) > 500,
            ]);
        }, $items, array_keys($items));
    }

    private function formatDate(string $date): string
    {
        if (empty($date)) {
            return '';
        }

        $timestamp = strtotime($date);
        $now = time();
        $diff = $now - $timestamp;

        if ($diff < 86400) {
            return 'Heute';
        }

        if ($diff < 172800) {
            return 'Gestern';
        }

        if ($diff < 604800) {
            $days = floor($diff / 86400);

            return "Vor {$days} Tagen";
        }

        return date('d.m.Y', $timestamp);
    }

    private function formatNumber(int $number): string
    {
        if ($number >= 1000000) {
            return round($number / 1000000, 1) . 'M';
        }

        if ($number >= 1000) {
            return round($number / 1000, 1) . 'K';
        }

        return (string) $number;
    }

    private function getPageSizeOptions(int $currentPageSize): array
    {
        $options = [10, 20, 50, 100];

        return array_map(function ($size) use ($currentPageSize) {
            return [
                'value' => $size,
                'label' => "{$size} pro Seite",
                'isActive' => $size === $currentPageSize,
            ];
        }, $options);
    }
}
