<?php

namespace App\Services\Meet;

use App\Models\Invitation;
use App\Models\Room;
use App\Models\User;
use Illuminate\Support\Str;

class InvitationService
{
    public function __construct(
        protected MeetNotificationService $notifications,
    ) {}

    /**
     * @param  array<int, array<string, mixed>>  $invites
     */
    public function inviteToRoom(Room $room, array $invites, User $host): void
    {
        $defaultRole = $room->isSpace() ? 'attendee' : 'participant';

        $normalized = collect($invites)->map(function ($invite) use ($defaultRole) {
            $email = trim((string) ($invite['email'] ?? ''));
            if ($email === '') {
                return null;
            }

            $user = User::where('email', $email)->first();

            return [
                'email' => $email,
                'name' => $invite['name'] ?? $invite['display_name'] ?? $user?->name,
                'role' => $invite['role'] ?? $defaultRole,
                'user_ref' => $invite['user_ref'] ?? $user?->ownerRef(),
            ];
        })->filter()->unique('email')->values()->all();

        $this->notifications->sendInvitations($room, $normalized, $host);
    }

    public function resend(Invitation $invitation, User $host): Invitation
    {
        $this->notifications->sendInvitationEmail($invitation->room, $invitation, $host);
        $invitation->update(['sent_at' => now()]);

        return $invitation->fresh();
    }

    public function respond(Invitation $invitation, string $status, ?string $token = null): Invitation
    {
        abort_unless(in_array($status, ['accepted', 'declined'], true), 422);
        if ($token !== null) {
            abort_unless(hash_equals((string) $invitation->rsvp_token, $token), 403);
        }

        $invitation->update([
            'status' => $status,
            'responded_at' => now(),
        ]);

        return $invitation->fresh();
    }

    public function markAcceptedOnJoin(Room $room, ?User $user, ?string $email): void
    {
        $query = $room->invitations()->where('status', 'pending');

        if ($user) {
            $query->where(function ($q) use ($user, $email) {
                $q->where('user_ref', $user->ownerRef());
                if ($email) {
                    $q->orWhere('email', $email);
                }
            });
        } elseif ($email) {
            $query->where('email', $email);
        } else {
            return;
        }

        $query->update(['status' => 'accepted', 'responded_at' => now()]);
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public function parseCsv(string $content): array
    {
        $lines = preg_split('/\r\n|\r|\n/', trim($content)) ?: [];
        $invites = [];

        foreach ($lines as $index => $line) {
            $line = trim($line);
            if ($line === '' || ($index === 0 && str_contains(strtolower($line), 'email'))) {
                continue;
            }

            $parts = str_getcsv($line);
            $email = trim((string) ($parts[0] ?? ''));
            if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
                continue;
            }

            $invites[] = [
                'email' => $email,
                'name' => trim((string) ($parts[1] ?? '')) ?: null,
                'role' => trim((string) ($parts[2] ?? '')) ?: 'participant',
            ];
        }

        return $invites;
    }

    public function bulkFromCsv(Room $room, string $csvContent, User $host): int
    {
        $invites = $this->parseCsv($csvContent);
        $this->inviteToRoom($room, $invites, $host);

        return count($invites);
    }
}
