<?php

namespace App\Services\Care;

use App\Models\Member;

class CarePermissions
{
    /**
     * Role abilities.
     *
     * Lab catalog pricing uses `lab.catalog.manage` (admins via `*`, plus `lab_manager`).
     * Lab technicians keep `lab.manage` for queue / sample / process / results —
     * not catalog CRUD or price edits.
     *
     * Blood Bank operational inventory uses `blood_bank.manage` (managers + admins).
     * Clinical visit stage/issue for managers also requires specialty module manage.
     *
     * @var array<string, list<string>>
     */
    protected array $roleAbilities = [
        'super_admin' => ['*'],
        'hospital_admin' => ['*'],
        'receptionist' => [
            'dashboard.view', 'patients.view', 'patients.manage',
            'appointments.view', 'appointments.manage', 'queue.manage',
            'service_queues.console',
        ],
        'doctor' => [
            'dashboard.view', 'patients.view', 'appointments.view',
            'consultations.view', 'consultations.manage',
            'investigations.request', 'prescriptions.manage',
            'lab.view', 'lab.results.view',
            'assessments.view', 'assessments.capture', 'assessments.manage',
            'pathways.manage',
            'service_queues.console',
        ],
        'nurse' => [
            'dashboard.view', 'patients.view', 'appointments.view',
            'consultations.view', 'vitals.manage',
            'service_queues.console',
            'assessments.view', 'assessments.capture',
        ],
        'lab_technician' => [
            'dashboard.view', 'patients.view', 'lab.view', 'lab.manage',
            'service_queues.console',
        ],
        'lab_manager' => [
            'dashboard.view', 'patients.view', 'lab.view', 'lab.manage',
            'lab.catalog.manage',
            'service_queues.console',
        ],
        'pharmacist' => [
            'dashboard.view', 'patients.view', 'prescriptions.view', 'prescriptions.dispense',
            'pharmacy.view', 'pharmacy.manage',
            'service_queues.console',
        ],
        'blood_bank_manager' => [
            'dashboard.view', 'patients.view',
            'blood_bank.view', 'blood_bank.manage',
            'service_queues.console',
        ],
        // Cashiers run the Billing desk (bills / payments). They do not get
        // Ladill POS app access — see filterAllowedAppSlugs() / DemoWorld.
        'cashier' => [
            'dashboard.view', 'patients.view', 'bills.view', 'bills.manage', 'payments.manage',
            'service_queues.console',
        ],
        'accountant' => [
            'dashboard.view', 'bills.view', 'reports.finance.view', 'reports.finance.export',
            'audit.view', 'audit.export',
        ],
    ];

    /** @var list<string> */
    protected array $adminAbilities = [
        'admin.branches.view', 'admin.branches.manage',
        'admin.departments.view', 'admin.departments.manage',
        'admin.practitioners.view', 'admin.practitioners.manage',
        'admin.members.view', 'admin.members.manage',
        'settings.view', 'settings.manage',
        'lab.catalog.manage',
        'blood_bank.view', 'blood_bank.manage',
        'devices.view', 'devices.manage',
        'displays.view', 'displays.manage',
        'audit.view', 'audit.export',
    ];

    public function can(?Member $member, string $ability): bool
    {
        if ($member === null) {
            return false;
        }

        $abilities = $this->roleAbilities[$member->role] ?? [];

        if (in_array('*', $abilities, true)) {
            return true;
        }

        return in_array($ability, $abilities, true);
    }

    public function isAdmin(?Member $member): bool
    {
        return $member !== null && in_array($member->role, ['super_admin', 'hospital_admin'], true);
    }

    /**
     * Floor care: queues, specialty clinics, lab/pharmacy counters.
     * Facility admins manage settings/staff — they do not staff waiting lines.
     */
    public function handlesFloorCare(?Member $member): bool
    {
        if ($member === null || $this->isAdmin($member)) {
            return false;
        }

        return in_array($member->role, [
            'doctor',
            'nurse',
            'lab_technician',
            'lab_manager',
            'pharmacist',
            'blood_bank_manager',
            'receptionist',
            'cashier',
        ], true);
    }

    /**
     * Dedicated patient-flow board (GP Queue home / call-next board).
     * Doctors only — nurses, reception, pharmacy, and other floor roles use
     * specialty module lists and service queues instead.
     * Facility admins manage settings/staff and do not staff this board.
     */
    public function canAccessPatientQueue(?Member $member): bool
    {
        return $member !== null && $member->role === 'doctor';
    }

    /**
     * Care cashiers collect via Billing, not Ladill POS. Strip POS from
     * Identity app grants so the suite launcher hides it.
     *
     * @param  list<string>|null  $slugs  Null = unrestricted owner access.
     * @return list<string>|null
     */
    public function filterAllowedAppSlugs(?Member $member, ?array $slugs): ?array
    {
        if ($slugs === null || $member?->role !== 'cashier') {
            return $slugs;
        }

        return array_values(array_filter(
            array_map('strval', $slugs),
            fn (string $slug) => $slug !== 'pos',
        ));
    }

    /**
     * @param  array{full_access?: bool, apps?: list<string>, show_hub?: bool, show_billing?: bool}  $access
     * @return array{full_access?: bool, apps?: list<string>, show_hub?: bool, show_billing?: bool}
     */
    public function filterStaffAppAccess(?Member $member, array $access): array
    {
        if ($member?->role !== 'cashier') {
            return $access;
        }

        $apps = $this->filterAllowedAppSlugs($member, array_values(array_map(
            'strval',
            (array) ($access['apps'] ?? []),
        ))) ?? [];

        $access['apps'] = $apps;

        if (empty($access['full_access']) && count($apps) <= 1) {
            $access['show_hub'] = false;
        }

        return $access;
    }
}
