<?php

declare(strict_types=1);

namespace App\Application\LiveComponents\CommentThread;

use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\Attributes\LiveComponent;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\LiveComponents\ValueObjects\ComponentRenderData;

/**
 * CommentThreadComponent - Collaborative comment thread with replies and reactions
 *
 * Demonstrates:
 * - Type-safe state management with CommentThreadState Value Object
 * - Nested comment replies
 * - Comment reactions (like, emoji)
 * - Real-time comment updates
 * - User mentions
 * - Comment editing and deletion
 * - Sorting (newest, oldest, most liked)
 * - Compile-time type safety for data access
 */
#[LiveComponent('comment-thread')]
final readonly class CommentThreadComponent implements LiveComponentContract
{
    public function __construct(
        public ComponentId $id,
        public CommentThreadState $state
    ) {}
    public function getRenderData(): ComponentRenderData
    {
        // Build comment tree
        $commentTree = $this->state->buildCommentTree();

        // Prepare comments for display
        $preparedComments = $this->prepareCommentsForDisplay($commentTree);

        // Get statistics
        $statistics = $this->state->getStatistics();

        return new ComponentRenderData(
            templatePath: 'livecomponent-comment-thread',
            data: [
                // Raw data
                'comments' => $this->state->comments,
                'sort_by' => $this->state->sortBy,
                'show_reactions' => $this->state->showReactions,
                'allow_edit' => $this->state->allowEdit,
                'allow_delete' => $this->state->allowDelete,
                'max_nesting_level' => $this->state->maxNestingLevel,

                // Display data
                'prepared_comments' => $preparedComments,
                'has_comments' => $statistics['has_comments'],
                'total_comments' => $statistics['total_comments'],
                'top_level_count' => $statistics['top_level_count'],
                'total_reactions' => $statistics['total_reactions'],
                'sort_label' => $this->state->getSortLabel(),
                'sort_options' => $this->state->getSortOptions(),
            ]
        );
    }

    // Action methods - Type-safe parameters with SSE support

    #[Action]
    public function addComment(
        string $content,
        string $authorId,
        string $authorName,
        ?string $parentId = null
    ): CommentThreadState {
        return $this->state->withCommentAdded($content, $authorId, $authorName, $parentId);
    }

    #[Action]
    public function editComment(string $commentId, string $newContent): CommentThreadState
    {
        return $this->state->withCommentEdited($commentId, $newContent);
    }

    #[Action]
    public function deleteComment(string $commentId): CommentThreadState
    {
        return $this->state->withCommentDeleted($commentId);
    }

    #[Action]
    public function addReaction(string $commentId, string $reaction, string $userId): CommentThreadState
    {
        return $this->state->withReactionToggled($commentId, $reaction, $userId);
    }

    #[Action]
    public function changeSorting(string $sortBy): CommentThreadState
    {
        return $this->state->withSorting($sortBy);
    }

    /**
     * Get SSE channel for real-time comment updates
     *
     * Uses comments-scoped channel for context-based comment threads.
     * Extract context from component ID instance identifier.
     *
     * Examples:
     * - "comment-thread:post-123" → "comments:post-123"
     * - "comment-thread:article-456" → "comments:article-456"
     * - "comment-thread:global" → "comments:global"
     */
    public function getSseChannel(): string
    {
        // Extract context from component instance ID
        // ComponentId format: "comment-thread:post-123" or "comment-thread:article-456"
        $context = $this->id->instanceId;

        // Comments channel for context-based updates
        return "comments:{$context}";
    }

    // Helper methods

    private function prepareCommentsForDisplay(array $commentTree): array
    {
        return array_map(function ($comment) {
            $reactions = $comment['reactions'] ?? [];
            $groupedReactions = $this->groupReactions($reactions);

            $prepared = [
                'id' => $comment['id'],
                'content' => $comment['content'],
                'author_name' => $comment['author_name'],
                'created_at' => $comment['created_at'],
                'updated_at' => $comment['updated_at'],
                'is_edited' => $comment['is_edited'] ?? false,
                'level' => $comment['level'] ?? 0,
                'reply_count' => $comment['reply_count'] ?? 0,

                // Display properties
                'formatted_date' => $this->formatDate($comment['created_at']),
                'edited_label' => ($comment['is_edited'] ?? false) ? ' (bearbeitet)' : '',
                'indent_style' => 'margin-left: ' . (($comment['level'] ?? 0) * 2) . 'rem;',
                'has_replies' => ! empty($comment['replies']),

                // Reactions
                'show_reactions' => $this->state->showReactions,
                'grouped_reactions' => $groupedReactions,
                'total_reactions' => count($reactions),
                'has_reactions' => ! empty($reactions),

                // Actions
                'can_edit' => $this->state->allowEdit,
                'can_delete' => $this->state->allowDelete,
                'can_reply' => ($comment['level'] ?? 0) < ($this->state->maxNestingLevel - 1),

                // Nested replies
                'replies' => ! empty($comment['replies'])
                    ? $this->prepareCommentsForDisplay($comment['replies'])
                    : [],
            ];

            return $prepared;
        }, $commentTree);
    }

    private function groupReactions(array $reactions): array
    {
        $grouped = [];

        foreach ($reactions as $reaction) {
            $type = $reaction['type'];
            if (! isset($grouped[$type])) {
                $grouped[$type] = [
                    'type' => $type,
                    'count' => 0,
                    'users' => [],
                ];
            }
            $grouped[$type]['count']++;
            $grouped[$type]['users'][] = $reaction['user_id'];
        }

        return array_values($grouped);
    }

    private function formatDate(int $timestamp): string
    {
        $diff = time() - $timestamp;

        if ($diff < 60) {
            return 'gerade eben';
        }
        if ($diff < 3600) {
            $minutes = floor($diff / 60);

            return "vor {$minutes} Minute" . ($minutes > 1 ? 'n' : '');
        }
        if ($diff < 86400) {
            $hours = floor($diff / 3600);

            return "vor {$hours} Stunde" . ($hours > 1 ? 'n' : '');
        }

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