<?php

namespace Modules\Transport\Services;

use App\Models\ActivityLogModel;
use App\Models\TransportLocationModel;
use App\Models\TransportRouteModel;
use App\Models\TransportRouteStopModel;

class RouteService
{
    protected TransportRouteModel $routes;
    protected TransportRouteStopModel $stops;
    protected TransportLocationModel $locations;
    protected ActivityLogModel $activity;

    public function __construct()
    {
        $this->routes    = new TransportRouteModel();
        $this->stops     = new TransportRouteStopModel();
        $this->locations = new TransportLocationModel();
        $this->activity  = new ActivityLogModel();
    }

    public function create(array $input, ?int $actingUserId): array
    {
        $name = trim((string) ($input['name'] ?? ''));
        if ($name === '') {
            return ['success' => false, 'errors' => ['name' => 'Route name is required.']];
        }

        $originId = $this->resolveLocationId($input['origin_location_id'] ?? null);
        if ($originId === false) {
            return ['success' => false, 'errors' => ['origin_location_id' => 'Select a valid origin location.']];
        }

        $destId = $this->resolveLocationId($input['destination_location_id'] ?? null);
        if ($destId === false) {
            return ['success' => false, 'errors' => ['destination_location_id' => 'Select a valid destination location.']];
        }

        $data = $this->mapInput($input, $actingUserId);
        $data['number']                  = $this->routes->nextNumber();
        $data['name']                    = $name;
        $data['origin_location_id']      = $originId;
        $data['destination_location_id'] = $destId;
        $data['created_by']              = $actingUserId;
        $data['updated_by']              = $actingUserId;

        if (! $this->routes->insert($data, true)) {
            return ['success' => false, 'errors' => $this->routes->errors()];
        }

        $id = (int) $this->routes->getInsertID();
        $this->syncStops($id, $input);
        $this->activity->log('transport_routes', 'created', $actingUserId, "Created route #{$id} ({$data['number']})", (string) $id);

        return ['success' => true, 'id' => $id];
    }

    public function update(int $id, array $input, ?int $actingUserId): array
    {
        if (! $this->routes->find($id)) {
            return ['success' => false, 'errors' => ['id' => 'Route not found.']];
        }

        $name = trim((string) ($input['name'] ?? ''));
        if ($name === '') {
            return ['success' => false, 'errors' => ['name' => 'Route name is required.']];
        }

        $originId = $this->resolveLocationId($input['origin_location_id'] ?? null);
        if ($originId === false) {
            return ['success' => false, 'errors' => ['origin_location_id' => 'Select a valid origin location.']];
        }

        $destId = $this->resolveLocationId($input['destination_location_id'] ?? null);
        if ($destId === false) {
            return ['success' => false, 'errors' => ['destination_location_id' => 'Select a valid destination location.']];
        }

        $data = $this->mapInput($input, $actingUserId);
        $data['name']                    = $name;
        $data['origin_location_id']      = $originId;
        $data['destination_location_id'] = $destId;
        $data['updated_by']              = $actingUserId;

        if (! $this->routes->update($id, $data)) {
            return ['success' => false, 'errors' => $this->routes->errors()];
        }

        $this->syncStops($id, $input);
        $this->activity->log('transport_routes', 'updated', $actingUserId, "Updated route #{$id}", (string) $id);

        return ['success' => true];
    }

    public function delete(int $id, ?int $actingUserId): array
    {
        if (! $this->routes->find($id)) {
            return ['success' => false, 'error' => 'Route not found.'];
        }

        $this->stops->deleteForRoute($id);
        $this->routes->delete($id);
        $this->activity->log('transport_routes', 'deleted', $actingUserId, "Deleted route #{$id}", (string) $id);

        return ['success' => true];
    }

    protected function syncStops(int $routeId, array $input): void
    {
        $this->stops->deleteForRoute($routeId);

        $locationIds = $input['stop_location_id'] ?? [];
        $offsets     = $input['stop_offset_minutes'] ?? [];
        if (! is_array($locationIds)) {
            return;
        }

        $order = 1;
        foreach ($locationIds as $idx => $locId) {
            $locId = (int) $locId;
            if ($locId <= 0) {
                continue;
            }
            if (! $this->locations->find($locId)) {
                continue;
            }

            $offset = isset($offsets[$idx]) && $offsets[$idx] !== ''
                ? (int) $offsets[$idx]
                : null;

            $this->stops->insert([
                'route_id'                         => $routeId,
                'location_id'                      => $locId,
                'stop_order'                       => $order++,
                'estimated_arrival_offset_minutes' => $offset,
            ]);
        }
    }

    protected function mapInput(array $input, ?int $actingUserId): array
    {
        $status = (string) ($input['status'] ?? 'active');
        if (! in_array($status, ['active', 'inactive'], true)) {
            $status = 'active';
        }

        $distance = trim((string) ($input['distance_km'] ?? ''));
        $duration = trim((string) ($input['estimated_duration_minutes'] ?? ''));

        return [
            'code'                         => trim((string) ($input['code'] ?? '')) ?: null,
            'distance_km'                  => $distance !== '' ? round((float) $distance, 2) : null,
            'estimated_duration_minutes'   => $duration !== '' ? (int) $duration : null,
            'route_geometry'               => trim((string) ($input['route_geometry'] ?? '')) ?: null,
            'status'                       => $status,
            'notes'                        => trim((string) ($input['notes'] ?? '')) ?: null,
        ];
    }

    protected function resolveLocationId($value): int|null|false
    {
        if ($value === null || $value === '') {
            return null;
        }
        $id = (int) $value;
        $loc = $this->locations->find($id);

        return ($loc && $loc['status'] === 'active') ? $id : false;
    }
}
