<?php

namespace App\Http\Controllers;

use App\Services\DemoService;
use App\Services\MeetupService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

class MeetupController extends Controller
{
    public function __construct(
        private MeetupService $meetup,
        private DemoService $demo,
    ) {}

    public function index(): View
    {
        try {
            if ($this->demo->isEnabled()) {
                $this->demo->ensureSharedSandbox();
            }
        } catch (\Throwable) {
            // Demo sandbox is optional for Pass boot.
        }

        return view('mexco.index');
    }

    public function committee(): View
    {
        return view('mexco.committee');
    }

    public function events(Request $request): JsonResponse
    {
        return response()->json($this->meetup->listEventsForApi($request->boolean('public')));
    }

    public function findAccount(Request $request): JsonResponse
    {
        $request->validate([
            'email' => 'required|email',
            'ic' => 'nullable|string',
            'password' => 'nullable|string',
        ]);

        $ic = $request->input('ic') ?? $request->input('password');

        $result = $this->meetup->findAccount(
            $request->input('email'),
            $ic,
        );

        if (! ($result['ok'] ?? false)) {
            return response()->json($result, 422);
        }

        $request->session()->put('meetup_pending', [
            'email' => $result['email'],
            'slug' => $result['slug'],
            'name' => $result['name'],
            'ic' => $result['ic'],
            'matches' => $result['matches'],
        ]);
        $request->session()->put('meetup_last_email', $result['email']);

        return response()->json($result);
    }

    public function login(Request $request): JsonResponse
    {
        return $this->findAccount($request);
    }

    /**
     * MeXCo Attend login: organiser-registered email + IC.
     * Session only includes events where the user has COMMITTEE/ORGANISER role.
     */
    public function attendLogin(Request $request): JsonResponse
    {
        $request->validate([
            'email' => 'required|email',
            'ic' => 'nullable|string',
            'password' => 'nullable|string',
        ]);

        $ic = $request->input('ic') ?? $request->input('password');

        $result = $this->meetup->findAttendAccount(
            $request->input('email'),
            $ic,
        );

        if (! ($result['ok'] ?? false)) {
            return response()->json($result, 422);
        }

        $request->session()->put('meetup_pending', [
            'email' => $result['email'],
            'slug' => $result['slug'],
            'name' => $result['name'],
            'ic' => $result['ic'],
            'matches' => $result['matches'],
            'attend' => true,
        ]);
        $request->session()->put('meetup_attend', true);
        $request->session()->put('meetup_last_email', $result['email']);

        return response()->json($result);
    }

    /**
     * Open an Attend event the committee member is registered for.
     */
    public function attendEnter(Request $request, string $eventId): JsonResponse
    {
        $pending = $request->session()->get('meetup_pending');
        if (! $pending || empty($pending['attend'])) {
            return response()->json(['error' => 'Not authenticated'], 401);
        }

        $match = collect($pending['matches'] ?? [])->firstWhere('eventId', $eventId);
        if (! $match || ! $this->meetup->hasCommitteeAccess($match)) {
            return response()->json(['error' => 'Event not in your committee list'], 403);
        }

        $request->session()->put('meetup_org_'.$eventId, true);
        $request->session()->put('meetup_event', $eventId);
        $request->session()->put('meetup_slug', $pending['slug']);
        $request->session()->put('meetup_last_email', $pending['email']);
        $request->session()->put('meetup_attend', true);

        return response()->json([
            'ok' => true,
            'eventId' => $eventId,
            'eventName' => $match['shortName'] ?? $match['eventName'] ?? $eventId,
            'role' => $match['role'] ?? 'COMMITTEE',
            'name' => $pending['name'] ?? null,
        ]);
    }

    public function authSession(Request $request): JsonResponse
    {
        $pending = $request->session()->get('meetup_pending');
        if (! $pending) {
            return response()->json(['ok' => false]);
        }

        return response()->json([
            'ok' => true,
            'email' => $pending['email'] ?? null,
            'name' => $pending['name'] ?? null,
            'slug' => $pending['slug'] ?? null,
            'matches' => $pending['matches'] ?? [],
            'attend' => (bool) ($pending['attend'] ?? $request->session()->get('meetup_attend')),
        ]);
    }

    public function enterEvent(Request $request, string $eventId): JsonResponse
    {
        $pending = $request->session()->get('meetup_pending');
        if (! $pending) {
            return response()->json(['error' => 'Not authenticated'], 401);
        }

        $match = collect($pending['matches'])->firstWhere('eventId', $eventId);
        if (! $match && ! $request->session()->get('meetup_org_'.$eventId)) {
            return response()->json(['error' => 'Event not in your list'], 403);
        }

        $participant = $this->meetup->getParticipant($eventId, $pending['slug']);
        if (! $participant && $match) {
            $participant = $this->meetup->saveParticipant($eventId, $pending['slug'], [
                'email' => $pending['email'],
                'name' => $match['name'],
                'org' => $match['org'],
                'ic' => $match['ic'],
                'phone' => $match['phone'],
                'role' => $match['role'],
                'stamps' => [],
                'sessions' => [],
            ]);
        }

        $request->session()->put('meetup_event', $eventId);
        $request->session()->put('meetup_slug', $pending['slug']);
        $request->session()->put('meetup_last_email', $pending['email']);

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

    public function orgAccess(Request $request, string $eventId): JsonResponse
    {
        $request->validate([
            'password' => 'nullable|string',
            'passcode' => 'nullable|string',
        ]);

        $secret = $request->input('password') ?? $request->input('passcode');

        if (! $secret || ! $this->meetup->verifyOrganiserPassword($eventId, $secret)) {
            return response()->json(['error' => 'Wrong password.'], 422);
        }

        $request->session()->put('meetup_org_'.$eventId, true);
        $request->session()->put('meetup_event', $eventId);

        return response()->json(['ok' => true]);
    }

    public function signOut(Request $request): JsonResponse
    {
        $keys = array_keys($request->session()->all());
        foreach ($keys as $key) {
            if (str_starts_with($key, 'meetup_')) {
                $request->session()->forget($key);
            }
        }

        return response()->json(['ok' => true]);
    }

    public function lastEmail(Request $request): JsonResponse
    {
        return response()->json([
            'email' => $request->session()->get('meetup_last_email'),
        ]);
    }

    public function config(string $eventId): JsonResponse
    {
        return response()->json($this->meetup->getEventConfig($eventId));
    }

    public function participant(Request $request, string $eventId): JsonResponse
    {
        $slug = $request->session()->get('meetup_slug');
        if (! $slug) {
            return response()->json(['error' => 'Not authenticated'], 401);
        }

        if ($request->isMethod('get')) {
            $p = $this->meetup->getParticipant($eventId, $slug);

            return response()->json($p ?? []);
        }

        $data = $request->validate([
            'email' => 'sometimes|email',
            'name' => 'sometimes|string',
            'org' => 'nullable|string',
            'ic' => 'nullable|string',
            'phone' => 'nullable|string',
            'role' => 'nullable|string',
            'stamps' => 'nullable|array',
            'sessions' => 'nullable|array',
            'verified' => 'nullable',
        ]);

        return response()->json(
            $this->meetup->saveParticipant($eventId, $slug, $data)
        );
    }

    public function stamp(Request $request, string $eventId): JsonResponse
    {
        $slug = $request->session()->get('meetup_slug');
        if (! $slug) {
            return response()->json(['ok' => false, 'msg' => 'Not authenticated'], 401);
        }

        $request->validate(['code' => 'required|string']);

        return response()->json(
            $this->meetup->applyStamp($eventId, $slug, $request->input('code'))
        );
    }

    public function vote(Request $request, string $eventId): JsonResponse
    {
        $slug = $request->session()->get('meetup_slug');
        if (! $slug) {
            return response()->json(['ok' => false, 'msg' => 'Not authenticated'], 401);
        }

        $request->validate(['code' => 'required|string']);

        return response()->json(
            $this->meetup->castBoothVote($eventId, $slug, $request->input('code'))
        );
    }

    public function joinSession(Request $request, string $eventId, string $sessionKey): JsonResponse
    {
        $slug = $request->session()->get('meetup_slug');
        if (! $slug) {
            return response()->json(['ok' => false, 'msg' => 'Not authenticated'], 401);
        }

        return response()->json(
            $this->meetup->joinSession($eventId, $slug, $sessionKey)
        );
    }

    public function verify(Request $request, string $eventId, string $slug): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['ok' => false, 'msg' => 'Unauthorized'], 403);
        }

        return response()->json($this->meetup->verifyParticipant($eventId, $slug));
    }

    public function people(Request $request, string $eventId): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        return response()->json($this->meetup->listPeople($eventId));
    }

    public function saveSettings(Request $request, string $eventId): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $this->meetup->saveSettings($eventId, $request->all());

        return response()->json(['ok' => true]);
    }

    public function saveRoles(Request $request, string $eventId): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $this->meetup->saveRoles($eventId, $request->input('roles', []));

        return response()->json(['ok' => true]);
    }

    public function saveBooths(Request $request, string $eventId): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $this->meetup->saveBooths($eventId, $request->input('booths', []));

        return response()->json(['ok' => true]);
    }

    public function saveSessions(Request $request, string $eventId): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $this->meetup->saveSessions($eventId, $request->input('sessions', []));

        return response()->json(['ok' => true]);
    }

    public function saveRegistry(Request $request, string $eventId): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $this->meetup->saveRegistry($eventId, $request->input('registry', []));

        return response()->json(['ok' => true]);
    }

    public function upsertParticipant(Request $request, string $eventId): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $result = $this->meetup->upsertParticipant(
            $eventId,
            $request->input('editing_slug'),
            $request->only(['email', 'name', 'org', 'ic', 'phone', 'role']),
        );

        if (! ($result['ok'] ?? false)) {
            return response()->json($result, 422);
        }

        return response()->json($result);
    }

    public function deleteParticipant(Request $request, string $eventId, string $slug): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $this->meetup->deleteParticipant($eventId, $slug);

        return response()->json(['ok' => true]);
    }

    public function saveEvents(Request $request): JsonResponse
    {
        $eventId = $request->session()->get('meetup_event');
        if (! $eventId || ! $this->isOrganiser($request, $eventId)) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $this->meetup->saveEvents($request->input('events', []));

        return response()->json(['ok' => true]);
    }

    public function getParticipantBySlug(Request $request, string $eventId, string $slug): JsonResponse
    {
        if (! $this->isOrganiser($request, $eventId) && $request->session()->get('meetup_slug') !== $slug) {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        $p = $this->meetup->getParticipant($eventId, $slug);

        return response()->json($p ?? []);
    }

    protected function isOrganiser(Request $request, string $eventId): bool
    {
        return (bool) $request->session()->get('meetup_org_'.$eventId);
    }
}
