<?php

namespace App\Services;

use App\Models\Booking;
use App\Models\Company;
use App\Models\Driver;
use App\Models\DriverPayout;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class PayoutService
{
    /**
     * Creates one payout per driver who has completed, un-paid-out bookings
     * — "un-paid-out" meaning payout_id is still null, not a date range, so
     * a booking can never be double-counted or silently skipped regardless
     * of when it happened relative to the last payout run.
     *
     * @return Collection<int, DriverPayout>
     */
    public function generate(?int $companyId): Collection
    {
        $driverIds = Booking::query()
            ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
            ->whereNotNull('driver_id')
            ->whereNull('payout_id')
            ->whereHas('status', fn ($q) => $q->where('name', 'Completed'))
            ->distinct()
            ->pluck('driver_id');

        $payouts = collect();

        foreach ($driverIds as $driverId) {
            $driver = Driver::find($driverId);
            if (! $driver) {
                continue;
            }

            $payout = DB::transaction(function () use ($driver, $companyId) {
                $bookings = Booking::where('driver_id', $driver->id)
                    ->when($companyId, fn ($q) => $q->where('company_id', $companyId))
                    ->whereNull('payout_id')
                    ->whereHas('status', fn ($q) => $q->where('name', 'Completed'))
                    ->lockForUpdate()
                    ->get();

                if ($bookings->isEmpty()) {
                    return null;
                }

                $rate = $driver->effective_commission_rate;
                $totalFare = (float) $bookings->sum('fare_amount');
                $amount = round($totalFare * ($rate / 100), 2);

                $payout = DriverPayout::create([
                    'company_id' => $driver->company_id,
                    'driver_id' => $driver->id,
                    'bookings_count' => $bookings->count(),
                    'total_fare' => round($totalFare, 2),
                    'commission_rate_applied' => $rate,
                    'amount' => $amount,
                    'status' => 'pending',
                ]);

                Booking::whereIn('id', $bookings->pluck('id'))->update(['payout_id' => $payout->id]);

                return $payout;
            });

            if ($payout) {
                $payouts->push($payout);
            }
        }

        return $payouts;
    }
}
