<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\ArtworkComment;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

final class UserMentionSyncService
{
    public function syncForComment(ArtworkComment $comment): void
    {
        if (! Schema::hasTable('user_mentions')) {
            return;
        }

        $usernames = $this->extractMentions((string) ($comment->raw_content ?? $comment->content ?? ''));
        $mentionedIds = $usernames === []
            ? []
            : User::query()
                ->whereIn(DB::raw('LOWER(username)'), $usernames)
                ->where('is_active', true)
                ->whereNull('deleted_at')
                ->pluck('id')
                ->map(fn ($id) => (int) $id)
                ->all();

        DB::transaction(function () use ($comment, $mentionedIds): void {
            DB::table('user_mentions')
                ->where('comment_id', (int) $comment->id)
                ->delete();

            if ($mentionedIds === []) {
                return;
            }

            $rows = collect($mentionedIds)
                ->reject(fn (int $id) => $id === (int) $comment->user_id)
                ->unique()
                ->map(fn (int $mentionedUserId) => [
                    'user_id' => (int) $comment->user_id,
                    'mentioned_user_id' => $mentionedUserId,
                    'artwork_id' => (int) $comment->artwork_id,
                    'comment_id' => (int) $comment->id,
                    'created_at' => $comment->created_at ?? now(),
                ])
                ->values()
                ->all();

            if ($rows !== []) {
                DB::table('user_mentions')->insert($rows);
            }
        });
    }

    public function deleteForComment(int $commentId): void
    {
        if (! Schema::hasTable('user_mentions')) {
            return;
        }

        DB::table('user_mentions')->where('comment_id', $commentId)->delete();
    }

    private function extractMentions(string $content): array
    {
        preg_match_all('/(^|[^A-Za-z0-9_])@([A-Za-z0-9_-]{3,20})/', $content, $matches);

        return collect($matches[2] ?? [])
            ->map(fn ($username) => strtolower((string) $username))
            ->unique()
            ->values()
            ->all();
    }
}
