<?php

namespace App\Services\Meet\Media;

use Agence104\LiveKit\AccessToken;
use Agence104\LiveKit\AccessTokenOptions;
use Agence104\LiveKit\RoomCreateOptions;
use Agence104\LiveKit\RoomServiceClient;
use Agence104\LiveKit\VideoGrant;
use Illuminate\Support\Facades\Log;

class LiveKitProvider implements MediaProviderInterface
{
    public function createRoom(string $roomName, array $options = []): void
    {
        if (! $this->isConfigured()) {
            return;
        }

        try {
            $client = new RoomServiceClient(
                $this->apiHost(),
                (string) config('meet.media.livekit.api_key'),
                (string) config('meet.media.livekit.api_secret'),
            );

            $client->createRoom(new RoomCreateOptions([
                'name' => $roomName,
                'empty_timeout' => (int) ($options['empty_timeout'] ?? 300),
            ]));
        } catch (\Throwable $e) {
            Log::warning('LiveKit createRoom failed.', [
                'room' => $roomName,
                'error' => $e->getMessage(),
            ]);
        }
    }

    public function deleteRoom(string $roomName): void
    {
        if (! $this->isConfigured() || $roomName === '') {
            return;
        }

        try {
            $client = new RoomServiceClient(
                $this->apiHost(),
                (string) config('meet.media.livekit.api_key'),
                (string) config('meet.media.livekit.api_secret'),
            );

            $client->deleteRoom($roomName);
        } catch (\Throwable $e) {
            Log::warning('LiveKit deleteRoom failed.', [
                'room' => $roomName,
                'error' => $e->getMessage(),
            ]);
        }
    }

    public function generateToken(
        string $roomName,
        string $identity,
        string $displayName,
        array $grants = [],
    ): string {
        $apiKey = (string) config('meet.media.livekit.api_key');
        $apiSecret = (string) config('meet.media.livekit.api_secret');

        $tokenOptions = (new AccessTokenOptions())
            ->setIdentity($identity)
            ->setName($displayName)
            ->setTtl(3600);

        $videoGrant = (new VideoGrant())
            ->setRoomJoin()
            ->setRoomName($roomName)
            ->setCanPublish($grants['can_publish'] ?? true)
            ->setCanSubscribe($grants['can_subscribe'] ?? true)
            ->setCanPublishData($grants['can_publish_data'] ?? true);

        if ($grants['room_admin'] ?? false) {
            $videoGrant->setRoomAdmin();
        }

        return (new AccessToken($apiKey, $apiSecret))
            ->init($tokenOptions)
            ->setGrant($videoGrant)
            ->toJwt();
    }

    public function isConfigured(): bool
    {
        return filled(config('meet.media.livekit.url'))
            && filled(config('meet.media.livekit.api_key'))
            && filled(config('meet.media.livekit.api_secret'));
    }

    public function serverUrl(): string
    {
        return (string) config('meet.media.livekit.url');
    }

    public function apiHost(): string
    {
        $override = (string) config('meet.media.livekit.api_url', '');
        if ($override !== '') {
            return rtrim($override, '/');
        }

        $url = (string) config('meet.media.livekit.url', '');

        return (string) preg_replace('#^wss:#', 'https:', (string) preg_replace('#^ws:#', 'http:', $url));
    }
}
