<?php

namespace App\Services;

class DispatchService
{
    public function nearbyPractitioners(?int $serviceId, ?float $lat, ?float $lng, int $limit = 12): array
    {
        $db = db_connect();
        $builder = $db->table('practitioner_profiles pp')
            ->select('pp.*, u.full_name, u.avatar, pl.latitude, pl.longitude')
            ->join('users u', 'u.id = pp.user_id')
            ->join('practitioner_locations pl', 'pl.practitioner_id = pp.id AND pl.is_current = 1', 'left')
            ->where('pp.verification_status', 'verified')
            ->where('pp.is_online', 1)
            ->where('u.status', 'active');
        if ($serviceId) {
            $builder->select('ps.price as service_price')
                ->join('practitioner_services ps', 'ps.practitioner_id = pp.id AND ps.is_active = 1', 'inner')
                ->where('ps.service_id', $serviceId);
        } else {
            $builder->select('(SELECT MIN(ps2.price) FROM practitioner_services ps2 WHERE ps2.practitioner_id = pp.id AND ps2.is_active = 1) AS service_price', false);
        }
        $rawRows = $builder->get()->getResultArray();
        $rows = [];
        foreach ($rawRows as $raw) $rows[(int)$raw['id']] = $raw;
        $rows = array_values($rows);
        foreach ($rows as &$row) {
            $row['distance_km'] = ($lat !== null && $lng !== null && $row['latitude'] !== null && $row['longitude'] !== null)
                ? $this->distance($lat, $lng, (float)$row['latitude'], (float)$row['longitude']) : null;
            $row['eta_minutes'] = $row['distance_km'] !== null ? max(8, (int) round($row['distance_km'] * 3.2 + 6)) : null;
        }
        unset($row);
        usort($rows, fn($a,$b) => ($a['distance_km'] ?? 9999) <=> ($b['distance_km'] ?? 9999));
        return array_slice($rows, 0, $limit);
    }

    public function assignBest(int $careRequestId): ?array
    {
        $db = db_connect();
        $request = $db->table('care_requests')->where('id', $careRequestId)->get()->getRowArray();
        if (! $request) return null;
        $lat=$request['latitude']!==null?(float)$request['latitude']:null; $lng=$request['longitude']!==null?(float)$request['longitude']:null;
        $candidates = $this->nearbyPractitioners((int)$request['service_id'], $lat, $lng, 5);
        foreach ($candidates as $candidate) {
            $exists = $db->table('care_request_assignments')->where(['care_request_id'=>$careRequestId,'practitioner_id'=>$candidate['id']])->countAllResults();
            if ($exists) continue;
            $db->table('care_request_assignments')->insert([
                'care_request_id' => $careRequestId,
                'practitioner_id' => $candidate['id'],
                'status' => 'offered',
                'offered_at' => date('Y-m-d H:i:s'),
                'expires_at' => date('Y-m-d H:i:s', time()+180),
                'created_at' => date('Y-m-d H:i:s'),
            ]);
            $requester = $db->table('users')->select('id')->where('id', $candidate['user_id'])->get()->getRowArray();
            if ($requester) (new NotificationService())->create((int)$requester['id'], 'New care request', 'A nearby patient needs care.', 'request', '/practitioner/requests');
            return $candidate;
        }
        return null;
    }

    private function distance(float $lat1, float $lon1, float $lat2, float $lon2): float
    {
        $earth = 6371;
        $dLat = deg2rad($lat2-$lat1); $dLon = deg2rad($lon2-$lon1);
        $a = sin($dLat/2)**2 + cos(deg2rad($lat1))*cos(deg2rad($lat2))*sin($dLon/2)**2;
        return round($earth * 2 * atan2(sqrt($a), sqrt(1-$a)), 1);
    }
}
