<?php

namespace Modules\Transport\Services;

use App\Models\ActivityLogModel;
use App\Models\TransportDriverModel;
use App\Models\TransportRouteModel;
use App\Models\TransportScheduleModel;
use App\Models\TransportScheduleStopModel;
use App\Models\TransportVehicleModel;

class ScheduleService
{
    protected TransportScheduleModel $schedules;
    protected TransportScheduleStopModel $scheduleStops;
    protected TransportRouteModel $routes;
    protected TransportVehicleModel $vehicles;
    protected TransportDriverModel $drivers;
    protected ActivityLogModel $activity;

    public function __construct()
    {
        $this->schedules     = new TransportScheduleModel();
        $this->scheduleStops = new TransportScheduleStopModel();
        $this->routes    = new TransportRouteModel();
        $this->vehicles  = new TransportVehicleModel();
        $this->drivers   = new TransportDriverModel();
        $this->activity  = new ActivityLogModel();
    }

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

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

        $routeId = $this->resolveRouteId($input['route_id'] ?? null);
        if ($routeId === false) {
            return ['success' => false, 'errors' => ['route_id' => 'Select a valid route.']];
        }

        $vehicleId = $this->resolveVehicleId($input['vehicle_id'] ?? null);
        if ($vehicleId === false) {
            return ['success' => false, 'errors' => ['vehicle_id' => 'Select a valid active vehicle.']];
        }

        $driverId = $this->resolveDriverId($input['driver_id'] ?? null);
        if ($driverId === false) {
            return ['success' => false, 'errors' => ['driver_id' => 'Select a valid active driver.']];
        }

        $data = $this->mapInput($input, $actingUserId);
        $data['number']         = $this->schedules->nextNumber();
        $data['title']          = $title;
        $data['schedule_date']  = $date;
        $data['route_id']       = $routeId;
        $data['vehicle_id']     = $vehicleId;
        $data['driver_id']      = $driverId;
        $data['created_by']     = $actingUserId;
        $data['updated_by']     = $actingUserId;

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

        $id = (int) $this->schedules->getInsertID();
        $this->activity->log('transport_scheduling', 'created', $actingUserId, "Created schedule #{$id} ({$data['number']})", (string) $id);

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

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

        if (! in_array($schedule['status'], ['planned', 'scheduled'], true)) {
            return ['success' => false, 'errors' => ['status' => 'Only planned or scheduled trips can be edited.']];
        }

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

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

        $routeId = $this->resolveRouteId($input['route_id'] ?? null);
        if ($routeId === false) {
            return ['success' => false, 'errors' => ['route_id' => 'Select a valid route.']];
        }

        $vehicleId = $this->resolveVehicleId($input['vehicle_id'] ?? null);
        if ($vehicleId === false) {
            return ['success' => false, 'errors' => ['vehicle_id' => 'Select a valid active vehicle.']];
        }

        $driverId = $this->resolveDriverId($input['driver_id'] ?? null);
        if ($driverId === false) {
            return ['success' => false, 'errors' => ['driver_id' => 'Select a valid active driver.']];
        }

        $data = $this->mapInput($input, $actingUserId);
        $data['title']         = $title;
        $data['schedule_date'] = $date;
        $data['route_id']      = $routeId;
        $data['vehicle_id']    = $vehicleId;
        $data['driver_id']     = $driverId;
        $data['updated_by']    = $actingUserId;

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

        $this->activity->log('transport_scheduling', 'updated', $actingUserId, "Updated schedule #{$id}", (string) $id);

        return ['success' => true];
    }

    public function transition(int $id, string $status, ?int $actingUserId): array
    {
        $schedule = $this->schedules->find($id);
        if (! $schedule) {
            return ['success' => false, 'error' => 'Schedule not found.'];
        }

        $allowed = [
            'scheduled'   => ['planned'],
            'in_progress' => ['scheduled'],
            'completed'   => ['in_progress', 'scheduled'],
            'cancelled'   => ['planned', 'scheduled', 'in_progress'],
        ];

        if (! isset($allowed[$status]) || ! in_array($schedule['status'], $allowed[$status], true)) {
            return ['success' => false, 'error' => 'Invalid status transition.'];
        }

        $patch = ['status' => $status, 'updated_by' => $actingUserId];
        if ($status === 'in_progress') {
            $patch['started_at'] = date('Y-m-d H:i:s');
        }
        if ($status === 'completed') {
            $patch['completed_at'] = date('Y-m-d H:i:s');
        }

        $this->schedules->update($id, $patch);
        $this->activity->log('transport_scheduling', $status, $actingUserId, "Schedule #{$id} → {$status}", (string) $id);

        return ['success' => true];
    }

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

        if (! in_array($schedule['status'], ['planned', 'cancelled'], true)) {
            return ['success' => false, 'error' => 'Only planned or cancelled schedules can be deleted.'];
        }

        $this->schedules->delete($id);
        $this->scheduleStops->deleteForSchedule($id);
        $this->activity->log('transport_scheduling', 'deleted', $actingUserId, "Deleted schedule #{$id}", (string) $id);

        return ['success' => true];
    }

    protected function mapInput(array $input, ?int $actingUserId): array
    {
        $priority = (string) ($input['priority'] ?? 'normal');
        if (! in_array($priority, TransportScheduleModel::PRIORITIES, true)) {
            $priority = 'normal';
        }

        $status = (string) ($input['status'] ?? 'planned');
        if (! in_array($status, ['planned', 'scheduled'], true)) {
            $status = 'planned';
        }

        return [
            'departure_time'        => $this->nullableTime($input['departure_time'] ?? null),
            'arrival_time'          => $this->nullableTime($input['arrival_time'] ?? null),
            'shift_start_time'      => $this->nullableTime($input['shift_start_time'] ?? null),
            'shift_end_time'        => $this->nullableTime($input['shift_end_time'] ?? null),
            'return_departure_time' => $this->nullableTime($input['return_departure_time'] ?? null),
            'return_arrival_time'   => $this->nullableTime($input['return_arrival_time'] ?? null),
            'priority'              => $priority,
            'status'                => $status,
            'notes'                 => trim((string) ($input['notes'] ?? '')) ?: null,
        ];
    }

    protected function nullableTime($value): ?string
    {
        $v = trim((string) ($value ?? ''));

        return $v !== '' ? $v : null;
    }

    protected function resolveRouteId($value): int|null|false
    {
        if ($value === null || $value === '') {
            return null;
        }
        $id = (int) $value;
        $route = $this->routes->find($id);

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

    protected function resolveVehicleId($value): int|null|false
    {
        if ($value === null || $value === '') {
            return null;
        }
        $id = (int) $value;
        $vehicle = $this->vehicles->find($id);

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

    protected function resolveDriverId($value): int|null|false
    {
        if ($value === null || $value === '') {
            return null;
        }
        $id = (int) $value;
        $driver = $this->drivers->find($id);

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