<?php

namespace Modules\Transport\Services;

use App\Models\ActivityLogModel;
use App\Models\EmployeeModel;
use App\Models\TransportDriverModel;
use App\Models\TransportLocationModel;
use App\Models\TransportVehicleModel;

class VehicleService
{
    protected TransportVehicleModel $vehicles;
    protected TransportDriverModel $drivers;
    protected TransportLocationModel $locations;
    protected ActivityLogModel $activity;

    public function __construct()
    {
        $this->vehicles   = new TransportVehicleModel();
        $this->drivers    = new TransportDriverModel();
        $this->locations  = new TransportLocationModel();
        $this->activity   = new ActivityLogModel();
    }

    public function create(array $input, ?int $actingUserId): array
    {
        $registration = strtoupper(trim((string) ($input['registration_number'] ?? '')));
        if ($registration === '') {
            return ['success' => false, 'errors' => ['registration_number' => 'Registration number is required.']];
        }
        if ($this->vehicles->isRegistrationTaken($registration)) {
            return ['success' => false, 'errors' => ['registration_number' => 'That registration number is already in use.']];
        }

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

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

        $data = $this->mapInput($input, $actingUserId);
        $data['number']               = $this->vehicles->nextNumber();
        $data['registration_number']  = $registration;
        $data['current_driver_id']    = $driverId;
        $data['current_location_id']  = $locationId;
        $data['created_by']           = $actingUserId;
        $data['updated_by']           = $actingUserId;

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

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

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

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

        $registration = strtoupper(trim((string) ($input['registration_number'] ?? '')));
        if ($registration === '') {
            return ['success' => false, 'errors' => ['registration_number' => 'Registration number is required.']];
        }
        if ($this->vehicles->isRegistrationTaken($registration, $id)) {
            return ['success' => false, 'errors' => ['registration_number' => 'That registration number is already in use.']];
        }

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

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

        $data = $this->mapInput($input, $actingUserId);
        $data['registration_number'] = $registration;
        $data['current_driver_id']   = $driverId;
        $data['current_location_id'] = $locationId;
        $data['updated_by']          = $actingUserId;

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

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

        return ['success' => true];
    }

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

        $this->vehicles->delete($id);
        $this->activity->log('transport_vehicles', 'deleted', $actingUserId, "Deleted vehicle #{$id}", (string) $id);

        return ['success' => true];
    }

    protected function mapInput(array $input, ?int $actingUserId): array
    {
        $type = (string) ($input['vehicle_type'] ?? 'van');
        if (! in_array($type, TransportVehicleModel::TYPES, true)) {
            $type = 'van';
        }

        $fuel = (string) ($input['fuel_type'] ?? 'diesel');
        if (! in_array($fuel, TransportVehicleModel::FUELS, true)) {
            $fuel = 'diesel';
        }

        $status = (string) ($input['status'] ?? 'active');
        if (! in_array($status, TransportVehicleModel::STATUSES, true)) {
            $status = 'active';
        }

        return [
            'make'              => trim((string) ($input['make'] ?? '')) ?: null,
            'model'             => trim((string) ($input['model'] ?? '')) ?: null,
            'year'              => $this->nullableInt($input['year'] ?? null),
            'vehicle_type'      => $type,
            'fuel_type'         => $fuel,
            'capacity'          => $this->nullableInt($input['capacity'] ?? null),
            'odometer_km'       => $this->nullableInt($input['odometer_km'] ?? null),
            'last_service_date' => $this->nullableDate($input['last_service_date'] ?? null),
            'latitude'          => $this->nullableDecimal($input['latitude'] ?? null),
            'longitude'         => $this->nullableDecimal($input['longitude'] ?? null),
            'status'            => $status,
            'notes'             => trim((string) ($input['notes'] ?? '')) ?: null,
        ];
    }

    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;
    }

    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;
    }

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

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

    protected function nullableInt($value): ?int
    {
        if ($value === null || $value === '') {
            return null;
        }

        return (int) $value;
    }

    protected function nullableDecimal($value): ?float
    {
        if ($value === null || $value === '') {
            return null;
        }

        return round((float) $value, 7);
    }
}
