<?php

namespace App\Models;

use Config\Lookups;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Writer\SvgWriter;
use RuntimeException;

/**
 * Exactly one of guest_id / event_client_id should be set — see the
 * CreateEventsTable migration comment. Enforced in EventController::
 * create() rather than here or as a DB constraint, since it's only ever
 * set at creation time (the edit form doesn't let you change the client).
 */
class EventModel extends TenantModel
{
    protected $table            = 'events';
    protected $primaryKey       = 'id';
    protected $useAutoIncrement = true;
    protected $returnType       = 'object';
    protected $useTimestamps    = true;

    protected $allowedFields = [
        'event_name',
        'event_type',
        'guest_id',
        'event_client_id',
        'event_date',
        'expected_headcount',
        'venue_space',
        'description',
        'status',
        'contract_notes',
        'public_token',
        'organizer_id',
    ];

    public function __construct()
    {
        parent::__construct();

        $statuses = array_keys((new Lookups())->eventStatuses);

        $this->validationRules = [
            'event_name' => 'required|max_length[150]',
            'event_date' => 'required|valid_date[Y-m-d]',
            'status'     => 'permit_empty|in_list[' . implode(',', $statuses) . ']',
        ];
    }

    public function withClient()
    {
        return $this->select("events.*, guests.full_name as guest_name,
                event_clients.company_name as company_name")
            ->join('guests', 'guests.id = events.guest_id', 'left')
            ->join('event_clients', 'event_clients.id = events.event_client_id', 'left');
    }

    /**
     * "Show all past events they've held" — Phase 2 spec, for whichever
     * kind of client this is.
     */
    public function historyForGuest(int $guestId): array
    {
        return $this->withClient()->where('events.guest_id', $guestId)->orderBy('events.event_date', 'desc')->findAll();
    }

    public function historyForClient(int $eventClientId): array
    {
        return $this->withClient()->where('events.event_client_id', $eventClientId)->orderBy('events.event_date', 'desc')->findAll();
    }

    public function countOn(string $date): int
    {
        return $this->where('event_date', $date)->where('status !=', 'cancelled')->countAllResults();
    }

    /** Public registration/check-in URLs use this instead of the raw id — see AddPublicTokenToEventsTable's migration comment. */
    public function findByPublicToken(string $token): ?object
    {
        return $this->where('public_token', $token)->first();
    }

    /**
     * Lazily generates and saves a token the first time a staff member
     * opens the event's page (EventController::show()) — no backfill
     * migration for pre-existing events, they just get one on next view.
     */
    public function ensurePublicToken(int $eventId): string
    {
        $event = $this->find($eventId);

        if ($event === null) {
            throw new RuntimeException("Event #{$eventId} not found.");
        }

        if (! empty($event->public_token)) {
            return $event->public_token;
        }

        $token = bin2hex(random_bytes(16));
        $this->update($eventId, ['public_token' => $token]);

        return $token;
    }

    /**
     * SVG, not PNG — needs neither GD nor Imagick (ext-imagick isn't
     * available on this server; SVG sidesteps the question entirely).
     * Returned as a data URI so the caller needs no extra route/action
     * just to serve an image. Shared by both the staff event page
     * (EventController::show()) and the event organizer portal
     * (EventOrganizerController::showEvent()) so there's one QR-builder
     * call site, not two that could drift apart.
     */
    public function registrationQrDataUri(string $checkinUrl): string
    {
        return (new Builder(writer: new SvgWriter(), data: $checkinUrl, size: 220, margin: 8))
            ->build()
            ->getDataUri();
    }
}
