<?php

namespace App\Models;

use App\Models\Concerns\BelongsToOwner;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;

class Room extends Model
{
    use BelongsToOwner, SoftDeletes;

    protected $table = 'meet_rooms';

    protected $fillable = [
        'uuid', 'owner_ref', 'organization_id', 'branch_id', 'host_user_ref',
        'title', 'description', 'type', 'status', 'slug', 'scheduled_at',
        'duration_minutes', 'timezone', 'passcode', 'settings', 'source', 'calendar_event_id',
        'recurring_series_id', 'recurrence_rule', 'recurrence_interval', 'recurrence_until',
    ];

    protected function casts(): array
    {
        return [
            'scheduled_at' => 'datetime',
            'recurrence_until' => 'date',
            'settings' => 'array',
            'source' => 'array',
        ];
    }

    protected static function booted(): void
    {
        static::creating(function (Room $room) {
            if (empty($room->uuid)) {
                $room->uuid = (string) Str::uuid();
            }
        });
    }

    public function getRouteKeyName(): string
    {
        return 'uuid';
    }

    public function organization(): BelongsTo
    {
        return $this->belongsTo(Organization::class, 'organization_id');
    }

    public function branch(): BelongsTo
    {
        return $this->belongsTo(Branch::class, 'branch_id');
    }

    public function sessions(): HasMany
    {
        return $this->hasMany(Session::class, 'room_id');
    }

    public function invitations(): HasMany
    {
        return $this->hasMany(Invitation::class, 'room_id');
    }

    public function webinarRegistrations(): HasMany
    {
        return $this->hasMany(WebinarRegistration::class, 'room_id');
    }

    public function sessionFiles(): HasMany
    {
        return $this->hasMany(SessionFile::class, 'room_id');
    }

    /**
     * @param  \Illuminate\Database\Eloquent\Builder<self>  $query
     */
    public function scopeForSource($query, string $app, string $entityId, ?string $ownerRef = null): void
    {
        $query->where('source->app', $app)
            ->where('source->entity_id', $entityId);

        if ($ownerRef !== null) {
            $query->where('owner_ref', $ownerRef);
        }
    }

    public function isWebinar(): bool
    {
        return $this->type === 'webinar';
    }

    public function isConference(): bool
    {
        return $this->type === 'town_hall';
    }

    public function isSpace(): bool
    {
        return $this->type === 'space';
    }

    public function isAudioOnly(): bool
    {
        return $this->isSpace() || (bool) $this->setting('audio_only', false);
    }

    public function canRestart(): bool
    {
        if ($this->status === 'cancelled' || $this->activeSession()) {
            return false;
        }

        return $this->status === 'ended'
            || $this->type === 'personal'
            || $this->status === 'scheduled';
    }

    public function restartLabel(): string
    {
        $restarting = $this->status === 'ended' || $this->sessions()->exists();

        if ($this->isWebinar()) {
            return $restarting ? 'Restart webinar' : 'Start webinar';
        }

        if ($this->isConference()) {
            return $restarting ? 'Restart conference' : 'Start conference';
        }

        if ($this->isSpace()) {
            return $restarting ? 'Reopen room' : 'Open room';
        }

        return $restarting ? 'Restart meeting' : 'Start meeting';
    }

    public function isTownHall(): bool
    {
        return $this->type === 'town_hall';
    }

    public function isRecurring(): bool
    {
        return filled($this->recurrence_rule);
    }

    public function activeSession(): ?Session
    {
        return $this->sessions()->where('status', 'live')->latest()->first();
    }

    public function setting(string $key, mixed $default = null): mixed
    {
        return data_get($this->settings, $key, data_get(config('meet.default_settings'), $key, $default));
    }

    public function safeTimezone(): string
    {
        $timezone = (string) ($this->timezone ?: 'UTC');

        try {
            new \DateTimeZone($timezone);

            return $timezone;
        } catch (\Throwable) {
            return 'UTC';
        }
    }

    public function isLive(): bool
    {
        return $this->status === 'live';
    }

    public function requiresWaitingRoom(?User $user, string $role): bool
    {
        if (! $this->setting('waiting_room', true)) {
            return false;
        }

        if ($role === 'host' || in_array($role, ['co_host', 'panelist'], true) || ($user && $user->ownerRef() === $this->host_user_ref)) {
            return false;
        }

        return true;
    }

    public function joinUrl(): string
    {
        return rtrim((string) config('app.meet_url', 'https://meet.ladill.com'), '/').'/r/'.$this->uuid;
    }

    public function isEventsLinked(): bool
    {
        return \App\Support\EventsSourceLink::isLinked($this);
    }

    public function hasEventsRegistrationInvite(?string $email): bool
    {
        if ($email === null || trim($email) === '') {
            return false;
        }

        return $this->invitations()
            ->where('email', $email)
            ->whereIn('status', ['pending', 'accepted'])
            ->exists();
    }
}
