<?php

namespace App\Http\Controllers\Meet;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Meet\Concerns\ScopesToAccount;
use App\Models\ContactGroup;
use App\Models\Invitation;
use App\Models\Room;
use App\Services\Meet\ContactService;
use App\Services\Meet\InvitationService;
use App\Support\EventsSourceLink;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;

class InvitationController extends Controller
{
    use ScopesToAccount;

    public function __construct(
        protected InvitationService $invitations,
        protected ContactService $contacts,
    ) {}

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

        if ($room->isWebinar() || $room->isConference()) {
            $adminUrl = EventsSourceLink::eventCommsUrl($room) ?? EventsSourceLink::eventAdminUrl($room);

            if ($adminUrl) {
                return redirect()->away($adminUrl);
            }

            $showRoute = $room->isWebinar() ? 'meet.webinars.show' : 'meet.conferences.show';

            return redirect()
                ->route($showRoute, $room)
                ->withErrors(['invitations' => 'Link this session to Ladill Events to send bulk invitations.']);
        }

        $room->load(['invitations' => fn ($q) => $q->orderByDesc('created_at')]);
        $groups = ContactGroup::owned($this->ownerRef($request))
            ->where('organization_id', $room->organization_id)
            ->withCount('members')
            ->orderBy('name')
            ->get();

        return view('meet.invitations.index', compact('room', 'groups'));
    }

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

        $validated = $request->validate([
            'emails' => ['nullable', 'string'],
            'member_refs' => ['nullable', 'array'],
            'member_refs.*' => ['string'],
            'contact_group_id' => ['nullable', 'integer', 'exists:meet_contact_groups,id'],
        ]);

        $invites = [];

        if ($emails = trim((string) ($validated['emails'] ?? ''))) {
            foreach (preg_split('/[\s,;]+/', $emails) as $email) {
                if ($email = trim($email)) {
                    $invites[] = ['email' => $email];
                }
            }
        }

        foreach ($validated['member_refs'] ?? [] as $userRef) {
            $user = \App\Models\User::where('public_id', $userRef)->first();
            if ($user?->email) {
                $invites[] = ['email' => $user->email, 'name' => $user->name, 'user_ref' => $userRef];
            }
        }

        if (! empty($validated['contact_group_id'])) {
            $group = ContactGroup::owned($this->ownerRef($request))->findOrFail($validated['contact_group_id']);
            $invites = array_merge($invites, $this->contacts->fromGroup($group)->all());
        }

        $this->invitations->inviteToRoom($room, $invites, $request->user());

        return back()->with('success', count($invites).' invitation(s) sent.');
    }

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

        $request->validate(['csv' => ['required', 'file', 'mimes:csv,txt', 'max:2048']]);
        $count = $this->invitations->bulkFromCsv($room, $request->file('csv')->getContent(), $request->user());

        return back()->with('success', "{$count} invitation(s) imported.");
    }

    public function resend(Request $request, Invitation $invitation): RedirectResponse
    {
        $this->authorizeAbility($request, 'meetings.manage');
        $this->authorizeOwner($request, $invitation);

        $this->invitations->resend($invitation, $request->user());

        return back()->with('success', 'Invitation resent.');
    }

    public function destroy(Request $request, Invitation $invitation): RedirectResponse
    {
        $this->authorizeAbility($request, 'meetings.manage');
        $this->authorizeOwner($request, $invitation);
        $room = $invitation->room;
        $invitation->delete();

        return redirect()->route('meet.invitations.index', $room)->with('success', 'Invitation removed.');
    }

    public function rsvp(Request $request, Invitation $invitation): View|RedirectResponse
    {
        abort_unless(hash_equals((string) $invitation->rsvp_token, (string) $request->query('token')), 403);

        if ($request->isMethod('post')) {
            $validated = $request->validate(['status' => ['required', 'in:accepted,declined']]);
            $this->invitations->respond($invitation, $validated['status'], $invitation->rsvp_token);

            return view('meet.invitations.rsvp-done', [
                'invitation' => $invitation->fresh(),
                'room' => $invitation->room,
            ]);
        }

        return view('meet.invitations.rsvp', [
            'invitation' => $invitation,
            'room' => $invitation->room,
        ]);
    }

    public function searchContacts(Request $request): JsonResponse
    {
        $this->authorizeAbility($request, 'meetings.create');
        $organization = $this->organization($request);
        $query = (string) $request->query('q', '');

        $results = $this->contacts->search($organization->id, $this->ownerRef($request), $query);

        return response()->json(['contacts' => $results]);
    }
}
