<?php

namespace App\Services\Posts;

use App\Models\Post;
use App\Models\PostHashtag;
use Illuminate\Support\Facades\DB;

/**
 * Parses hashtags from post body and syncs them to the post_hashtags table.
 */
class PostHashtagService
{
    /** Regex: #word (letters/numbers/underscore, 2–64 chars, no leading digit) */
    private const HASHTAG_RE = '/#([A-Za-z][A-Za-z0-9_]{1,63})/u';

    /**
     * Extract unique lowercase hashtag strings from raw or HTML body.
     *
     * @return string[]
     */
    public function parseHashtags(string $body): array
    {
        $plainText = strip_tags($body);
        preg_match_all(self::HASHTAG_RE, $plainText, $matches);

        return array_values(array_unique(
            array_map('mb_strtolower', $matches[1] ?? [])
        ));
    }

    /**
     * Sync hashtags for a post: insert new, delete removed.
     */
    public function sync(Post $post, string $body): void
    {
        $tags = $this->parseHashtags($body);

        DB::transaction(function () use ($post, $tags) {
            // Remove tags no longer in the body
            PostHashtag::where('post_id', $post->id)
                ->whereNotIn('tag', $tags)
                ->delete();

            // Insert new tags (ignore duplicates)
            foreach ($tags as $tag) {
                PostHashtag::firstOrCreate([
                    'post_id' => $post->id,
                    'tag'     => $tag,
                ], [
                    'user_id'    => $post->user_id,
                    'created_at' => now(),
                ]);
            }
        });
    }

    /**
     * Trending hashtags in the last $hours hours (top $limit by post count).
     *
     * @return array<array{tag: string, post_count: int, author_count: int}>
     */
    public function trending(int $limit = 10, int $hours = 24): array
    {
        return DB::table('post_hashtags')
            ->join('posts', 'post_hashtags.post_id', '=', 'posts.id')
            ->where('post_hashtags.created_at', '>=', now()->subHours($hours))
            ->where('posts.status', Post::STATUS_PUBLISHED)
            ->where('posts.visibility', Post::VISIBILITY_PUBLIC)
            ->whereNull('posts.deleted_at')
            ->groupBy('post_hashtags.tag')
            ->orderByRaw('COUNT(*) DESC')
            ->limit($limit)
            ->get([
                'post_hashtags.tag',
                DB::raw('COUNT(*) as post_count'),
                DB::raw('COUNT(DISTINCT post_hashtags.user_id) as author_count'),
            ])
            ->map(fn ($row) => [
                'tag'          => $row->tag,
                'post_count'   => (int) $row->post_count,
                'author_count' => (int) $row->author_count,
            ])
            ->all();
    }
}
