<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Api\Concerns\ScopesApiToAccount;
use App\Models\Appointment;
use App\Models\Patient;
use App\Models\Visit;
use App\Services\Care\CarePermissions;
use App\Services\Care\OrganizationResolver;
use App\Services\Care\PatientService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class PatientController extends Controller
{
    use ScopesApiToAccount;

    public function __construct(
        protected PatientService $patients,
    ) {}

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

        $patients = $this->patients->search(
            $this->ownerRef($request),
            $organization->id,
            $request->only(['q', 'patient_number', 'phone', 'national_id', 'date_of_birth', 'per_page']),
            $branchScope,
        );

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

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

        $patient = $this->patients->create(
            $organization,
            $this->ownerRef($request),
            $this->validatedPatientData($request),
            $this->ownerRef($request),
        );

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

    public function show(Request $request, Patient $patient): JsonResponse
    {
        $this->authorizeAbility($request, 'patients.view');
        $this->authorizePatient($request, $patient);

        return response()->json($this->patients->dashboard($patient));
    }

    public function update(Request $request, Patient $patient): JsonResponse
    {
        $this->authorizeAbility($request, 'patients.manage');
        $this->authorizePatient($request, $patient);

        $updated = $this->patients->update(
            $patient,
            $this->ownerRef($request),
            $this->validatedPatientData($request),
            $this->ownerRef($request),
        );

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

    public function destroy(Request $request, Patient $patient): JsonResponse
    {
        $this->authorizeAbility($request, 'patients.manage');
        $this->authorizePatient($request, $patient);

        $this->patients->delete($patient, $this->ownerRef($request), $this->ownerRef($request));

        return response()->json(['message' => 'Patient archived.']);
    }

    protected function authorizePatient(Request $request, Patient $patient): void
    {
        $this->authorizeOwner($request, $patient);
        abort_unless($patient->organization_id === $this->organization($request)->id, 404);

        $branchScope = app(OrganizationResolver::class)->branchScope($this->member($request));
        if ($branchScope === null || $patient->branch_id === $branchScope) {
            return;
        }

        $hasLocalActivity = Visit::query()
            ->where('patient_id', $patient->id)
            ->where('organization_id', $patient->organization_id)
            ->where('branch_id', $branchScope)
            ->exists()
            || Appointment::query()
                ->where('patient_id', $patient->id)
                ->where('organization_id', $patient->organization_id)
                ->where('branch_id', $branchScope)
                ->exists();

        abort_unless($hasLocalActivity, 404);
    }

    /**
     * @return array<string, mixed>
     */
    protected function validatedPatientData(Request $request): array
    {
        return $request->validate([
            'branch_id' => ['nullable', 'integer', 'exists:care_branches,id'],
            'first_name' => ['required', 'string', 'max:100'],
            'last_name' => ['required', 'string', 'max:100'],
            'other_names' => ['nullable', 'string', 'max:100'],
            'gender' => ['nullable', 'string', 'in:'.implode(',', array_keys(config('care.genders')))],
            'date_of_birth' => ['nullable', 'date', 'before:today'],
            'phone' => ['nullable', 'string', 'max:30'],
            'email' => ['nullable', 'email', 'max:255'],
            'national_id' => ['nullable', 'string', 'max:50'],
            'address' => ['nullable', 'string', 'max:500'],
            'city' => ['nullable', 'string', 'max:100'],
            'region' => ['nullable', 'string', 'max:100'],
            'notes' => ['nullable', 'string', 'max:5000'],
            'allergies' => ['nullable', 'array'],
            'conditions' => ['nullable', 'array'],
            'family_history' => ['nullable', 'array'],
            'emergency_contacts' => ['nullable', 'array'],
            'insurance' => ['nullable', 'array'],
        ]);
    }
}
