<?php

namespace App\Http\Controllers\Api\V1;

use App\Enums\UserRole;
use App\Exceptions\DomainException;
use App\Http\Controllers\Controller;
use App\Http\Resources\DoctorResource;
use App\Http\Resources\LocationResource;
use App\Models\Doctor;
use App\Services\AccessService;
use App\Services\ScheduleService;
use App\Support\ApiResponse;
use Illuminate\Http\Request;

class DoctorController extends Controller
{
    use ApiResponse;

    public function __construct(
        private readonly AccessService $access,
        private readonly ScheduleService $schedule,
    ) {}

    public function index(Request $request)
    {
        $user = $request->user();

        $query = Doctor::query()
            ->with('user')
            ->where('organization_id', $user->organization_id)
            ->where('is_active', true);

        if ($request->filled('specialization')) {
            $query->where('specialization', 'like', '%'.$request->string('specialization').'%');
        }

        if ($request->filled('location_id')) {
            $query->whereHas('locationAssignments', fn ($q) => $q
                ->where('location_id', $request->integer('location_id'))
                ->where('is_active', true));
        }

        if ($user->role === UserRole::ASSISTANT && $user->assistant) {
            $query->whereHas('locationAssignments', function ($q) use ($user) {
                $q->whereExists(function ($sub) use ($user) {
                    $sub->selectRaw('1')
                        ->from('assistant_assignments as aa')
                        ->whereColumn('aa.doctor_id', 'doctor_location_assignments.doctor_id')
                        ->whereColumn('aa.location_id', 'doctor_location_assignments.location_id')
                        ->where('aa.assistant_id', $user->assistant->id)
                        ->where('aa.is_active', true);
                });
            });
        }

        if ($user->role === UserRole::DOCTOR && $user->doctor) {
            $query->whereKey($user->doctor->id);
        }

        return $this->success(DoctorResource::collection($query->orderBy('id')->get()));
    }

    public function locations(Request $request, Doctor $doctor)
    {
        $user = $request->user();

        if ($doctor->organization_id !== $user->organization_id || ! $doctor->is_active) {
            throw new DomainException('FORBIDDEN', 'Doctor is not available.', 403);
        }

        $query = $doctor->locationAssignments()
            ->with('location')
            ->where('is_active', true)
            ->whereHas('location', fn ($q) => $q->where('is_active', true));

        if ($user->role === UserRole::ASSISTANT && $user->assistant) {
            $query->whereExists(function ($sub) use ($user) {
                $sub->selectRaw('1')
                    ->from('assistant_assignments as aa')
                    ->whereColumn('aa.doctor_id', 'doctor_location_assignments.doctor_id')
                    ->whereColumn('aa.location_id', 'doctor_location_assignments.location_id')
                    ->where('aa.assistant_id', $user->assistant->id)
                    ->where('aa.is_active', true);
            });
        }

        if ($user->role === UserRole::DOCTOR && (int) $user->doctor?->id !== (int) $doctor->id) {
            throw new DomainException('FORBIDDEN', 'You cannot view another doctor context.', 403);
        }

        $assignments = $query->get();

        return $this->success($assignments->map(fn ($assignment) => [
            'assignment_id' => $assignment->id,
            'location' => new LocationResource($assignment->location),
            'consultation_fee' => (float) $assignment->consultation_fee,
            'followup_fee' => (float) $assignment->followup_fee,
            'slot_minutes' => $assignment->slot_minutes,
            'booking_window_days' => $assignment->booking_window_days,
            'cancellation_cutoff_minutes' => $assignment->cancellation_cutoff_minutes,
        ])->values());
    }

    public function availability(Request $request, Doctor $doctor)
    {
        $validated = $request->validate([
            'location_id' => ['required', 'integer'],
            'date' => ['required', 'date_format:Y-m-d'],
        ]);

        $user = $request->user();

        if ($doctor->organization_id !== $user->organization_id || ! $doctor->is_active) {
            throw new DomainException('FORBIDDEN', 'Doctor is not available.', 403);
        }

        if ($user->role === UserRole::ASSISTANT
            && ! $this->access->canUseDoctorLocation($user, $doctor->id, (int) $validated['location_id'])) {
            throw new DomainException('FORBIDDEN', 'This doctor/location is not assigned to you.', 403);
        }

        if ($user->role === UserRole::DOCTOR && (int) $user->doctor?->id !== (int) $doctor->id) {
            throw new DomainException('FORBIDDEN', 'You cannot view another doctor schedule.', 403);
        }

        $doctor->loadMissing('organization');

        return $this->success([
            'doctor_id' => $doctor->id,
            'location_id' => (int) $validated['location_id'],
            'date' => $validated['date'],
            'slots' => $this->schedule->availableSlots($doctor, (int) $validated['location_id'], $validated['date']),
        ]);
    }
}
