<?php

namespace App\Http\Controllers\Care;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Care\Concerns\ScopesToAccount;
use App\Models\Appointment;
use App\Models\Branch;
use App\Models\Member;
use App\Models\Practitioner;
use App\Services\Care\AppointmentService;
use App\Services\Care\CarePermissions;
use App\Services\Care\OrganizationResolver;
use App\Services\Care\ReportService;
use App\Services\Care\SpecialtyModuleService;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\View\View;

class DashboardController extends Controller
{
    use ScopesToAccount;

    public function __construct(
        protected ReportService $reports,
        protected CarePermissions $permissions,
        protected AppointmentService $appointments,
        protected SpecialtyModuleService $specialtyModules,
    ) {}

    public function index(Request $request): View
    {
        $this->authorizeAbility($request, 'dashboard.view');
        $organization = $this->organization($request);
        $owner = $this->ownerRef($request);
        $member = $this->member($request);

        $canBranches = $this->permissions->can($member, 'admin.branches.view');
        $canMembers = $this->permissions->can($member, 'admin.members.view');
        $canDepartments = $this->permissions->can($member, 'admin.departments.view');
        $canBills = $this->permissions->can($member, 'bills.view');
        $canFinance = $this->permissions->can($member, 'reports.finance.view');
        $canConsult = $this->permissions->can($member, 'consultations.manage');
        $showPatientQueue = $this->permissions->canAccessPatientQueue($member)
            && $this->permissions->can($member, 'appointments.view')
            && ! $canBranches;

        $branchQuery = Branch::owned($owner)->where('organization_id', $organization->id);
        $this->scopeToBranch($request, $branchQuery);

        $stats = [
            'branches' => $canBranches ? (clone $branchQuery)->where('is_active', true)->count() : 0,
            'team_members' => $canMembers
                ? Member::owned($owner)->where('organization_id', $organization->id)->count()
                : 0,
            'departments' => $canDepartments
                ? $organization->branches()
                    ->when(app(OrganizationResolver::class)->branchScope($member), function ($q, $branchId) {
                        $q->where('id', $branchId);
                    })
                    ->withCount('departments')
                    ->get()
                    ->sum('departments_count')
                : 0,
        ];

        $branches = $canBranches
            ? (clone $branchQuery)->withCount('departments')->orderBy('name')->get()
            : collect();

        $branchScope = app(OrganizationResolver::class)->branchScope($member);
        $operational = $this->reports->dashboardStats(
            $owner,
            $organization->id,
            $branchScope,
            includeBilling: $canBills || $canFinance,
        );

        [$queue, $inConsultation, $practitionerId] = $showPatientQueue
            ? $this->patientQueueForMember($request, $organization->id, $owner, $member, $branchScope)
            : [collect(), collect(), null];

        $showBillingPanel = $canBills;
        $paymentStats = $showBillingPanel
            ? $this->reports->todayPaymentStats($owner, $organization->id, $branchScope)
            : null;
        $recentPaidBills = $showBillingPanel
            ? $this->reports->recentPaidBills($owner, $organization->id, $branchScope)
            : collect();

        return view('care.dashboard', [
            'organization' => $organization,
            'member' => $member,
            'permissions' => $this->permissions,
            'stats' => $stats,
            'branches' => $branches,
            'operational' => $operational,
            'canBranches' => $canBranches,
            'canMembers' => $canMembers,
            'canDepartments' => $canDepartments,
            'canBills' => $canBills,
            'canFinance' => $canFinance,
            'canConsult' => $canConsult,
            'showPatientQueue' => $showPatientQueue,
            'patientQueue' => $queue,
            'inConsultation' => $inConsultation,
            'practitionerId' => $practitionerId,
            'specialtyModules' => $this->specialtyModules->enabledModulesForMember($organization, $member),
            'showBillingPanel' => $showBillingPanel,
            'paymentStats' => $paymentStats,
            'recentPaidBills' => $recentPaidBills,
        ]);
    }

    /**
     * @return array{0: Collection<int, Appointment>, 1: Collection<int, Appointment>, 2: ?int}
     */
    protected function patientQueueForMember(
        Request $request,
        int $organizationId,
        string $owner,
        ?Member $member,
        ?int $branchScope,
    ): array {
        $organization = $this->organization($request);
        $practitionerScope = app(OrganizationResolver::class)->practitionerScope($organization, $member);

        if ($practitionerScope !== null) {
            $queue = $this->appointments->queueForPractitioners($owner, $practitionerScope);
            $inConsultation = Appointment::owned($owner)
                ->where('organization_id', $organizationId)
                ->where('status', Appointment::STATUS_IN_CONSULTATION)
                ->whereIn('practitioner_id', $practitionerScope ?: [0])
                ->with(['patient', 'practitioner', 'consultation'])
                ->orderBy('started_at')
                ->limit(20)
                ->get();

            return [$queue, $inConsultation, $practitionerScope[0] ?? null];
        }

        $practitioner = null;
        if ($member) {
            $practitioner = Practitioner::owned($owner)
                ->where('organization_id', $organizationId)
                ->where('is_active', true)
                ->where(function ($query) use ($member) {
                    $query->where('member_id', $member->id)
                        ->orWhere('user_ref', $member->user_ref);
                })
                ->first();
        }

        $practitionerId = $practitioner?->id;
        $branchId = $branchScope
            ?? $practitioner?->branch_id
            ?? Branch::owned($owner)
                ->where('organization_id', $organizationId)
                ->where('is_active', true)
                ->orderBy('name')
                ->value('id');

        if (! $branchId) {
            return [collect(), collect(), $practitionerId];
        }

        $queue = $this->appointments->queue($owner, (int) $branchId, $practitionerId);

        $inConsultation = Appointment::owned($owner)
            ->where('organization_id', $organizationId)
            ->where('status', Appointment::STATUS_IN_CONSULTATION)
            ->where('branch_id', $branchId)
            ->when($practitionerId, fn ($q) => $q->where('practitioner_id', $practitionerId))
            ->with(['patient', 'practitioner', 'consultation'])
            ->orderBy('started_at')
            ->limit(20)
            ->get();

        return [$queue, $inConsultation, $practitionerId];
    }
}
