<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Api\Concerns\ScopesApiToAccount;
use App\Models\Appointment;
use App\Services\Care\AppointmentService;
use App\Services\Care\OrganizationResolver;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class AppointmentController extends Controller
{
    use ScopesApiToAccount;

    public function __construct(
        protected AppointmentService $appointments,
    ) {}

    public function index(Request $request): JsonResponse
    {
        $this->authorizeAbility($request, 'appointments.view');
        $organization = $this->organization($request);
        $branchScope = app(OrganizationResolver::class)->branchScope($this->member($request));

        $appointments = $this->appointments->list(
            $this->ownerRef($request),
            $organization->id,
            $request->only(['status', 'practitioner_id', 'date', 'patient_id', 'per_page']),
            $branchScope,
        );

        return response()->json($appointments);
    }

    public function store(Request $request): JsonResponse
    {
        $this->authorizeAbility($request, 'appointments.manage');
        $organization = $this->organization($request);

        $appointment = $this->appointments->book(
            $organization,
            $this->ownerRef($request),
            $this->validatedAppointmentData($request),
            $this->ownerRef($request),
        );

        return response()->json($appointment, 201);
    }

    public function walkIn(Request $request): JsonResponse
    {
        $this->authorizeAbility($request, 'appointments.manage');
        $organization = $this->organization($request);

        $appointment = $this->appointments->walkIn(
            $organization,
            $this->ownerRef($request),
            $this->validatedWalkInData($request),
            $this->ownerRef($request),
        );

        return response()->json($appointment, 201);
    }

    public function show(Request $request, Appointment $appointment): JsonResponse
    {
        $this->authorizeAbility($request, 'appointments.view');
        $this->authorizeAppointment($request, $appointment);

        return response()->json($appointment->load(['patient', 'practitioner', 'branch', 'visit', 'consultation']));
    }

    public function checkIn(Request $request, Appointment $appointment): JsonResponse
    {
        $this->authorizeAbility($request, 'appointments.manage');
        $this->authorizeAppointment($request, $appointment);

        $updated = $this->appointments->checkIn($appointment, $this->ownerRef($request), $this->ownerRef($request));

        return response()->json($updated);
    }

    public function cancel(Request $request, Appointment $appointment): JsonResponse
    {
        $this->authorizeAbility($request, 'appointments.manage');
        $this->authorizeAppointment($request, $appointment);

        $updated = $this->appointments->cancel($appointment, $this->ownerRef($request), $this->ownerRef($request));

        return response()->json($updated);
    }

    protected function authorizeAppointment(Request $request, Appointment $appointment): void
    {
        $this->authorizeOwner($request, $appointment);
        abort_unless($appointment->organization_id === $this->organization($request)->id, 404);

        $branchScope = app(OrganizationResolver::class)->branchScope($this->member($request));
        if ($branchScope !== null && $appointment->branch_id !== $branchScope) {
            abort(404);
        }
    }

    /**
     * @return array<string, mixed>
     */
    protected function validatedAppointmentData(Request $request): array
    {
        return $request->validate([
            'branch_id' => ['required', 'integer', 'exists:care_branches,id'],
            'patient_id' => ['required', 'integer', 'exists:care_patients,id'],
            'practitioner_id' => ['nullable', 'integer', 'exists:care_practitioners,id'],
            'department_id' => ['nullable', 'integer', 'exists:care_departments,id'],
            'scheduled_at' => ['required', 'date', 'after:now'],
            'reason' => ['nullable', 'string', 'max:1000'],
            'notes' => ['nullable', 'string', 'max:5000'],
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    protected function validatedWalkInData(Request $request): array
    {
        return $request->validate([
            'branch_id' => ['required', 'integer', 'exists:care_branches,id'],
            'patient_id' => ['required', 'integer', 'exists:care_patients,id'],
            'practitioner_id' => ['nullable', 'integer', 'exists:care_practitioners,id'],
            'department_id' => ['nullable', 'integer', 'exists:care_departments,id'],
            'reason' => ['nullable', 'string', 'max:1000'],
            'notes' => ['nullable', 'string', 'max:5000'],
        ]);
    }
}
