<?php

namespace App\Http\Controllers\Meet;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Meet\Concerns\BuildsMeetIndexPage;
use App\Http\Controllers\Meet\Concerns\ScopesToAccount;
use App\Models\Room;
use App\Services\Meet\AttendanceService;
use App\Services\Meet\AvailabilityService;
use App\Services\Meet\CalendarService;
use App\Services\Meet\IcalService;
use App\Services\Meet\InvitationService;
use App\Services\Meet\RecurringMeetingService;
use App\Services\Meet\RoomService;
use App\Services\Meet\SessionService;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;

class RoomController extends Controller
{
    use BuildsMeetIndexPage, ScopesToAccount;

    public function __construct(
        protected RoomService $rooms,
        protected SessionService $sessions,
        protected RecurringMeetingService $recurring,
        protected InvitationService $invitations,
        protected CalendarService $calendar,
        protected AvailabilityService $availability,
        protected IcalService $ical,
        protected AttendanceService $attendance,
    ) {}

    public function index(Request $request): View
    {
        $this->authorizeAbility($request, 'meetings.view');
        $organization = $this->organization($request);
        $owner = $this->ownerRef($request);

        $query = Room::owned($owner)->where('organization_id', $organization->id)
            ->whereNotIn('type', ['webinar', 'town_hall', 'space']);
        $this->scopeToBranch($request, $query);

        $rooms = $query->orderByDesc('scheduled_at')->paginate(20);

        $stats = $this->meetIndexStats($request, $query, 'Meetings', 'Live now');
        $items = $this->meetIndexItems($rooms, fn (Room $room) => route('meet.rooms.show', $room));

        return view('meet.rooms.index', compact('rooms', 'organization', 'stats', 'items'));
    }

    public function create(Request $request): View
    {
        $this->authorizeAbility($request, 'meetings.create');
        $organization = $this->organization($request);

        return view('meet.rooms.create', [
            'organization' => $organization,
            'timezones' => timezone_identifiers_list(),
            'recurrenceRules' => config('meet.recurrence_rules'),
            'defaultSettings' => config('meet.default_settings'),
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $this->authorizeAbility($request, 'meetings.create');
        $organization = $this->organization($request);

        $validated = $request->validate([
            'title' => ['required', 'string', 'max:255'],
            'description' => ['nullable', 'string', 'max:2000'],
            'type' => ['nullable', 'string', 'in:scheduled'],
            'scheduled_at' => ['nullable', 'date'],
            'duration_minutes' => ['nullable', 'integer', 'min:15', 'max:480'],
            'timezone' => ['nullable', 'timezone'],
            'passcode' => ['nullable', 'string', 'max:20'],
            'recurrence_rule' => ['nullable', 'string', 'in:'.implode(',', array_keys(config('meet.recurrence_rules')))],
            'recurrence_interval' => ['nullable', 'integer', 'min:1', 'max:12'],
            'recurrence_until' => ['nullable', 'date'],
            'invite_emails' => ['nullable', 'string'],
            'waiting_room' => ['sometimes', 'boolean'],
            'join_before_host' => ['sometimes', 'boolean'],
            'mute_on_join' => ['sometimes', 'boolean'],
            'auto_record' => ['sometimes', 'boolean'],
            'live_captions' => ['sometimes', 'boolean'],
            'webinar_auto_approve' => ['sometimes', 'boolean'],
        ]);

        $settings = [
            'waiting_room' => $request->boolean('waiting_room', true),
            'join_before_host' => $request->boolean('join_before_host'),
            'mute_on_join' => $request->boolean('mute_on_join', true),
            'auto_record' => $request->boolean('auto_record'),
            'live_captions' => $request->boolean('live_captions'),
            'webinar_auto_approve' => $request->boolean('webinar_auto_approve'),
            'stage_mode' => false,
        ];

        $data = array_merge($validated, [
            'settings' => $settings,
            'timezone' => $validated['timezone'] ?? $organization->timezone,
        ]);

        $isInstant = empty($validated['scheduled_at']);

        if (! empty($validated['recurrence_rule']) && ! $isInstant) {
            $room = $this->recurring->createSeries($request->user(), $organization, $data);
        } elseif ($isInstant) {
            $room = $this->rooms->createInstant($request->user(), $organization, $data);
        } else {
            $room = $this->rooms->createScheduled($request->user(), $organization, $data);
        }

        if ($emails = trim((string) ($validated['invite_emails'] ?? ''))) {
            $invites = collect(preg_split('/[\s,;]+/', $emails))
                ->filter()
                ->map(fn ($email) => ['email' => $email])
                ->all();
            $this->invitations->inviteToRoom($room, $invites, $request->user());
        }

        if (! $isInstant && $room->scheduled_at) {
            $this->calendar->syncRoomCreated($room, $request->user());
        }

        return redirect()->route('meet.rooms.show', $room)->with('success', 'Meeting created.');
    }

    public function show(Request $request, Room $room): View|RedirectResponse
    {
        $this->authorizeAbility($request, 'meetings.view');
        $this->authorizeOwner($request, $room);

        if ($room->isWebinar()) {
            return redirect()->route('meet.webinars.show', $room);
        }

        if ($room->isConference()) {
            return redirect()->route('meet.conferences.show', $room);
        }

        if ($room->isSpace()) {
            return redirect()->route('meet.spaces.show', $room);
        }

        $room->load(['sessions.participants', 'invitations', 'sessions.recordings', 'sessions.aiSummaries', 'sessionFiles', 'webinarRegistrations']);

        return view('meet.rooms.show', compact('room'));
    }

    public function start(Request $request, Room $room): RedirectResponse
    {
        $this->authorizeAbility($request, 'meetings.host');
        $this->authorizeOwner($request, $room);

        if ($room->status === 'cancelled') {
            return redirect()->route('meet.rooms.show', $room)
                ->withErrors(['start' => 'Meeting was cancelled.']);
        }

        if ($room->isTownHall() && $room->setting('green_room')) {
            $session = app(\App\Services\Meet\TownHallService::class)->startGreenRoom($room, $request->user());
        } else {
            $session = $this->sessions->start($room, $request->user());
        }

        $participant = $this->sessions->joinedParticipantForUser($session, $request->user());
        abort_unless($participant, 500, 'Unable to join as host.');

        $this->sessions->rememberParticipantSession($request, $participant, $session);

        return redirect()->route('meet.room', $session);
    }

    public function cancel(Request $request, Room $room): RedirectResponse
    {
        $this->authorizeAbility($request, 'meetings.manage');
        $this->authorizeOwner($request, $room);

        $this->rooms->cancel($room, $this->ownerRef($request), $request->user());

        return redirect()->route('meet.rooms.index')->with('success', 'Meeting cancelled.');
    }

    public function instant(Request $request): RedirectResponse
    {
        $this->authorizeAbility($request, 'meetings.create');
        $organization = $this->organization($request);

        $room = $this->rooms->createInstant($request->user(), $organization, [
            'title' => $request->user()->name."'s meeting",
        ]);

        $session = $this->sessions->start($room, $request->user());

        $participant = $this->sessions->joinedParticipantForUser($session, $request->user());
        abort_unless($participant, 500, 'Unable to join as host.');

        $this->sessions->rememberParticipantSession($request, $participant, $session);

        return redirect()->route('meet.room', $session);
    }

    public function personal(Request $request): RedirectResponse
    {
        $this->authorizeAbility($request, 'meetings.host');
        $organization = $this->organization($request);
        $room = $this->rooms->ensurePersonalRoom($request->user(), $organization);

        return redirect()->route('meet.rooms.show', $room);
    }

    public function ical(Request $request, Room $room): Response
    {
        $this->authorizeAbility($request, 'meetings.view');
        $this->authorizeOwner($request, $room);

        $content = $this->ical->forRoom($room, $request->user());

        return response($content, 200, [
            'Content-Type' => 'text/calendar; charset=utf-8',
            'Content-Disposition' => 'attachment; filename="meeting-'.$room->uuid.'.ics"',
        ]);
    }

    public function qr(Request $request, Room $room): Response
    {
        $this->authorizeAbility($request, 'meetings.view');
        $this->authorizeOwner($request, $room);

        $options = new QROptions(['outputType' => QRCode::OUTPUT_IMAGE_PNG, 'scale' => 8]);
        $binary = (new QRCode($options))->render($room->joinUrl());

        return response($binary, 200, ['Content-Type' => 'image/png']);
    }

    public function attendance(Request $request, Room $room): Response
    {
        $this->authorizeAbility($request, 'meetings.view');
        $this->authorizeOwner($request, $room);

        $session = $room->sessions()->latest()->first();
        abort_unless($session, 404);

        return response($this->attendance->toCsv($session), 200, [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="attendance-'.$room->uuid.'.csv"',
        ]);
    }
}
