<?php

namespace App\Services\Meet;

use App\Models\Participant;
use App\Models\User;
use Illuminate\Support\Collection;

class ParticipantPresenter
{
    /**
     * @param  Collection<int, Participant>  $participants
     */
    public static function avatarMap(Collection $participants, ?string $roomHostUserRef = null): Collection
    {
        $refs = $participants->pluck('user_ref')->filter();

        if ($roomHostUserRef) {
            $refs = $refs->push($roomHostUserRef)->unique();
        }

        if ($refs->isEmpty()) {
            return collect();
        }

        return User::query()
            ->whereIn('public_id', $refs->all())
            ->get()
            ->keyBy('public_id');
    }

    /**
     * @return array<string, mixed>
     */
    public static function toArray(Participant $participant, Collection $avatars, ?string $roomHostUserRef = null): array
    {
        return [
            'uuid' => $participant->uuid,
            'user_ref' => $participant->user_ref,
            'display_name' => $participant->display_name,
            'role' => $participant->role,
            'status' => $participant->status,
            'hand_raised' => $participant->hand_raised,
            'speak_requested' => (bool) $participant->speak_requested,
            'speak_granted' => (bool) $participant->speak_granted,
            'is_muted' => $participant->is_muted,
            'is_video_off' => $participant->is_video_off,
            'breakout_room_id' => $participant->breakout_room_id,
            'avatar_url' => self::avatarUrl($participant, $avatars, $roomHostUserRef),
        ];
    }

    public static function avatarUrl(Participant $participant, Collection $avatars, ?string $roomHostUserRef = null): ?string
    {
        if ($participant->user_ref) {
            $url = $avatars->get($participant->user_ref)?->avatarUrl();
            if ($url) {
                return $url;
            }
        }

        if (in_array($participant->role, ['host', 'co_host'], true) && $roomHostUserRef) {
            return $avatars->get($roomHostUserRef)?->avatarUrl();
        }

        return null;
    }

    /**
     * @param  list<array<string, mixed>>  $participants
     * @param  list<string>  $presenterRefs
     */
    public static function isSpeakerPerson(array $person, array $presenterRefs = []): bool
    {
        if (in_array($person['role'] ?? '', ['host', 'co_host', 'panelist'], true)) {
            return true;
        }

        $userRef = $person['user_ref'] ?? null;

        return is_string($userRef) && $userRef !== '' && in_array($userRef, $presenterRefs, true);
    }

    /**
     * @param  list<array<string, mixed>>  $participants
     * @param  list<string>  $presenterRefs
     */
    public static function headerCountNumber(array $participants, bool $usesStageLayout, array $presenterRefs = []): string
    {
        $joined = array_values(array_filter($participants, fn ($p) => ($p['status'] ?? '') === 'joined'));

        if ($usesStageLayout) {
            $count = count(array_filter($joined, fn ($p) => self::isSpeakerPerson($p, $presenterRefs)));
        } else {
            $count = count($joined);
        }

        return (string) $count;
    }

    /**
     * @param  list<array<string, mixed>>  $participants
     * @param  list<string>  $presenterRefs
     */
    public static function headerCountSuffix(array $participants, bool $usesStageLayout, array $presenterRefs = []): string
    {
        $joined = array_values(array_filter($participants, fn ($p) => ($p['status'] ?? '') === 'joined'));

        if ($usesStageLayout) {
            $count = count(array_filter($joined, fn ($p) => self::isSpeakerPerson($p, $presenterRefs)));

            return $count === 1 ? ' speaker' : ' speakers';
        }

        return ' in call';
    }

    /**
     * @param  list<array<string, mixed>>  $participants
     * @param  list<string>  $presenterRefs
     */
    public static function headerCountLabel(array $participants, bool $usesStageLayout, array $presenterRefs = []): string
    {
        return self::headerCountNumber($participants, $usesStageLayout, $presenterRefs)
            .self::headerCountSuffix($participants, $usesStageLayout, $presenterRefs);
    }

    /**
     * @param  list<array<string, mixed>>  $participants
     * @return array{display_name: string, avatar_url: ?string}|null
     */
    public static function headerHost(array $participants, array $roomHost): ?array
    {
        foreach ($participants as $person) {
            if (($person['status'] ?? '') !== 'joined') {
                continue;
            }

            if (in_array($person['role'] ?? '', ['host', 'co_host'], true)) {
                return [
                    'display_name' => (string) ($person['display_name'] ?? 'Host'),
                    'avatar_url' => $person['avatar_url'] ?? null,
                ];
            }
        }

        if (($roomHost['display_name'] ?? '') !== '') {
            return [
                'display_name' => (string) $roomHost['display_name'],
                'avatar_url' => $roomHost['avatar_url'] ?? null,
            ];
        }

        return null;
    }

    public static function initials(?string $name): string
    {
        $parts = preg_split('/\s+/', trim($name ?? '')) ?: [];
        $parts = array_values(array_filter($parts, fn ($part) => $part !== ''));

        if ($parts === []) {
            return '?';
        }

        if (count($parts) === 1) {
            return strtoupper(substr($parts[0], 0, 2));
        }

        return strtoupper(substr($parts[0], 0, 1).substr($parts[count($parts) - 1], 0, 1));
    }
}
