<?php

namespace App\Models;

use Config\Lookups;

/**
 * Admin/organizer-defined extra questions on one event's public
 * registration form — see CreateEventRegistrationFieldsTable's migration
 * comment. Reordering is plain move-up/move-down sort_order swaps, not
 * drag-and-drop — there's no drag-and-drop anywhere else in this app to
 * match, so plain buttons is the right level of interactivity.
 */
class EventRegistrationFieldModel extends TenantModel
{
    protected $table            = 'event_registration_fields';
    protected $primaryKey       = 'id';
    protected $useAutoIncrement = true;
    protected $returnType       = 'object';
    protected $useTimestamps    = true;

    protected $allowedFields = [
        'event_id',
        'label',
        'field_type',
        'options',
        'is_required',
        'sort_order',
    ];

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

        $types = array_keys((new Lookups())->eventRegistrationFieldTypes);

        $this->validationRules = [
            'event_id'    => 'required|integer',
            'label'       => 'required|max_length[150]',
            'field_type'  => 'required|in_list[' . implode(',', $types) . ']',
            'is_required' => 'permit_empty|in_list[0,1]',
        ];
    }

    public function forEvent(int $eventId): array
    {
        return $this->where('event_id', $eventId)->orderBy('sort_order', 'asc')->orderBy('id', 'asc')->findAll();
    }

    /** @return list<string> */
    public function decodedOptions(object $field): array
    {
        return empty($field->options) ? [] : (json_decode($field->options, true) ?: []);
    }

    public function nextSortOrder(int $eventId): int
    {
        $max = $this->where('event_id', $eventId)->selectMax('sort_order')->first();

        return ((int) ($max->sort_order ?? 0)) + 1;
    }

    /** Swaps this field's sort_order with the one immediately before it (within the same event). No-op if already first. */
    public function moveUp(int $id, int $eventId): void
    {
        $this->swapWithNeighbor($id, $eventId, 'up');
    }

    /** Swaps this field's sort_order with the one immediately after it (within the same event). No-op if already last. */
    public function moveDown(int $id, int $eventId): void
    {
        $this->swapWithNeighbor($id, $eventId, 'down');
    }

    private function swapWithNeighbor(int $id, int $eventId, string $direction): void
    {
        $field = $this->where('event_id', $eventId)->find($id);

        if ($field === null) {
            return;
        }

        $builder = $this->where('event_id', $eventId);

        $neighbor = $direction === 'up'
            ? $builder->where('sort_order <', $field->sort_order)->orderBy('sort_order', 'desc')->first()
            : $builder->where('sort_order >', $field->sort_order)->orderBy('sort_order', 'asc')->first();

        if ($neighbor === null) {
            return;
        }

        $this->update($field->id, ['sort_order' => $neighbor->sort_order]);
        $this->update($neighbor->id, ['sort_order' => $field->sort_order]);
    }
}
