<?php

namespace App\Services;

use App\Facades\Backoffice\BackendUserService;
use App\Models\Backoffice\Doctor;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\ModelNotFoundException;

class DoctorService
{
    /**
     * Get the doctor list for the backoffice grid
     *
     * @param $page
     * @param $rowCount
     * @param $sort
     * @param $search
     *
     * @return array
     */
    public function getDoctorGridList($page, $rowCount, $sort, $search)
    {
        Paginator::currentPageResolver( function () use ($page) {
            return $page;
        });

        if (!empty($search)) {
            $query = Doctor::where(function ($query) use ($search) {
                $query->orWhere('first_name', 'like', "%{$search}%")
                    ->orWhere('last_name', 'like', "%{$search}%");
            });
        } else {
            $query = Doctor::query();
        }

        $query->withCount('patients');

        if (empty($sort)) {
            $rows = $query->paginate($rowCount);
        } else {
            foreach ($sort as $field => $direction) {
                if(empty($direction) || !Str::is(strtolower($direction),"desc")){
                    $orderDirection = "asc";
                } else {
                    $orderDirection = $direction;
                }
                $rows = $query->orderBy($field, strtolower($orderDirection))->paginate($rowCount);
                break;
            }
        }

        return [
            "total"             => $rows->total(),
            "current"           => $rows->currentPage(),
            "rowCount"          => $rowCount,
            "rows"              => $rows->getCollection()
        ];
    }

    public function generateDoctorCode($doctorId)
    {
        $doctor = Doctor::findOrFail($doctorId);

        if(empty($doctor)){
            throw new ModelNotFoundException('Doctor not found');
        }

        // Generar un código único de 6 caracteres (letras minúsculas y números)
        do {
            $code = $this->generateRandomCode();
        } while (Doctor::where('code', $code)->exists());

        $doctor->code = $code;
        $doctor->save();

        return $doctor;
    }

    private function generateRandomCode()
    {
        $characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
        $code = '';

        for ($i = 0; $i < 6; $i++) {
            $code .= $characters[random_int(0, strlen($characters) - 1)];
        }

        return $code;
    }

    public function checkDoctorCode($data): ?Doctor
    {
        $doctor = Doctor::where('code', $data['code'])->first();

        if(empty($doctor)){
            throw new ModelNotFoundException('Doctor not found');
        }

        if ($doctor->code === $data['code'] && $doctor->status === Doctor::STATUS_ACTIVE) {
            return $doctor;
        }
        return null;
    }

    public function createDoctor($data)
    {
        $doctor = new Doctor();

        $loggedUser = BackendUserService::getLoggedUser();
        $doctor->backend_user_id = $loggedUser->id;

        if (!empty($data['first_name'])) {
            $doctor->first_name = $data['first_name'];
        }

        if (!empty($data['last_name'])) {
            $doctor->last_name = $data['last_name'];
        }

        $doctor->status = Doctor::STATUS_ACTIVE;

        if (!empty($data['institution'])) {
            $doctor->institution = $data['institution'];
        }

        $doctor->save();
        $doctor = $this->generateDoctorCode($doctor->id);

        return $doctor;
    }

    public function updateDoctor($doctorId, $data)
    {
        $doctor = Doctor::findOrFail($doctorId);

        if(empty($doctor)){
            abort(404);
        }

        $doctor->first_name = $data['first_name'];
        $doctor->last_name = $data['last_name'];
        $doctor->institution = $data['institution'];
        $doctor->status = $data['status'];

        $doctor->save();

        return $doctor;
    }

    public function list($data): Array
    {
        $query = Doctor::select('doctors.*');

        $orderDir = $data['orderDir'] ? $data['orderDir'] : 'asc';

        switch ($data['orderBy']) {
            default:
                # name
                $query->orderBy('doctors.first_name', $orderDir)
                    ->orderBy('doctors.last_name', $orderDir);
                break;
        }

        $perPage = $data['perPage'] ?? 12;
        $page = $data['page'] ?? 1;

        $doctors = $query->paginate($perPage, ['*'], 'page', $page);

        $paginationData = [
            'currentPage' =>  intval($doctors->currentPage()),
            'lastPage' => intval($doctors->lastPage()),
            'perPage' =>  intval($doctors->perPage()),
            'total' =>  intval($doctors->total()),
            'count' =>  intval($doctors->count()),
            'hasMorePages' => $doctors->hasMorePages(),
            'nextPageUrl' => $doctors->nextPageUrl(),
            'prevPageUrl' => $doctors->previousPageUrl(),
        ];

        return [
            'doctors' => $doctors,
            'pagination' => $paginationData,
        ];
    }

    public function update(Doctor $doctor, Array $data): Doctor
    {
        $doctor->first_name = $data['firstName'];
        $doctor->last_name = $data['lastName'];

        $doctor->save();

        return $doctor;
    }

    public function getDoctor($doctorId)
    {
        $doctor = Doctor::find($doctorId);
        return $doctor;
    }
}
