<?php

namespace App\Libraries;

use Config\Database;
use Modules\Trip\Models\PickdropModel;
use Modules\Trip\Models\SubtripModel;

/**
 * Ordered pick/drop points for a main trip (physical bus route).
 *
 * pickdrops.trip_id references subtrips.id (usually the "main" subtrip row).
 */
class TripPickdropRoute
{
    /** @var array<int, list<array{id: int, stand_id: int, type: int}>> */
    private static array $cache = [];

    /**
     * @return list<array{id: int, stand_id: int, type: int}>
     */
    public static function buildForTrip(int $tripId): array
    {
        if ($tripId <= 0) {
            return [];
        }

        if (isset(self::$cache[$tripId])) {
            return self::$cache[$tripId];
        }

        $mainSubtrip = (new SubtripModel())
            ->where('trip_id', $tripId)
            ->where('type', 'main')
            ->first();

        if (! $mainSubtrip) {
            self::$cache[$tripId] = [];

            return [];
        }

        $route = [];
        foreach ((new PickdropModel())
            ->select('id, stand_id, type')
            ->where('trip_id', (int) $mainSubtrip->id)
            ->orderBy('id', 'ASC')
            ->findAll() as $row) {
            $route[] = [
                'id' => (int) ($row->id ?? 0),
                'stand_id' => (int) ($row->stand_id ?? 0),
                'type' => (int) ($row->type ?? 0),
            ];
        }

        self::$cache[$tripId] = $route;

        return $route;
    }

    /**
     * Default boarding / alighting pickdrops for a subtrip (first pickup, last drop on that subtrip).
     *
     * @return array{pick: int, drop: int}
     */
    public static function resolveSubtripEndpointStandIds(int $subtripId, int $mainTripId = 0): array
    {
        $db = Database::connect();

        $resolveFromTripKey = static function (int $tripKey) use ($db): array {
            $pickRow = $db->table('pickdrops')
                ->select('id')
                ->where('trip_id', $tripKey)
                ->where('type', 1)
                ->orderBy('id', 'ASC')
                ->get()
                ->getRow();

            $dropRow = $db->table('pickdrops')
                ->select('id')
                ->where('trip_id', $tripKey)
                ->where('type', 2)
                ->orderBy('id', 'DESC')
                ->get()
                ->getRow();

            return [
                'pick' => $pickRow ? (int) $pickRow->id : 0,
                'drop' => $dropRow ? (int) $dropRow->id : 0,
            ];
        };

        if ($subtripId > 0) {
            $endpoints = $resolveFromTripKey($subtripId);
            if ($endpoints['pick'] > 0 && $endpoints['drop'] > 0) {
                return $endpoints;
            }
        }

        if ($mainTripId > 0) {
            $mainSub = (new SubtripModel())
                ->where('trip_id', $mainTripId)
                ->where('type', 'main')
                ->first();
            if ($mainSub) {
                return $resolveFromTripKey((int) $mainSub->id);
            }
        }

        return ['pick' => 0, 'drop' => 0];
    }

    /**
     * @param list<array{id: int, stand_id: int, type?: int}> $route
     */
    public static function indexOnRoute(array $route, $pickdropOrStandId): ?int
    {
        $id = (int) $pickdropOrStandId;
        if ($id <= 0 || $route === []) {
            return null;
        }

        foreach ($route as $idx => $point) {
            if ((int) $point['id'] === $id) {
                return (int) $idx;
            }
        }

        foreach ($route as $idx => $point) {
            if ((int) $point['stand_id'] === $id) {
                return (int) $idx;
            }
        }

        return null;
    }
}
