<?php

namespace App\Models;

use App\Traits\Auditable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use App\Models\Interfaces\IPostCreateAppointmentStructure;
use App\Models\Patients;
use DateTime;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
use App\Models\DoctorSchedule;
use App\Models\Especiality;
use App\Models\User;
use App\Models\UserProfile;

/**
 * @property string $id
 * @property string $patients_id
 * @property string $date
 * @property integer $active
 * @property string $especiality
 * @property string $created_at
 * @property string $updated_at
 * @property Patient $patient
 */
class Appointments extends Model
{
    use Auditable;
    /**
     * The "type" of the auto-incrementing ID.
     * 
     * @var string
     */
    protected $keyType = 'string';

    /**
     * Indicates if the IDs are auto-incrementing.
     * 
     * @var bool
     */
    public $incrementing = false;

    // Modelo User.php
    protected $dateFormat = 'Y-m-d H:i:s.u'; // Formato con microsegundos

    /**
     * @var array
     */
    protected $fillable = ['id','users_id','patients_id','code', 'date', 'active','deleted', 'especiality','summary', 'created_at', 'updated_at', 'status', 'closed_by', 'closed_at'];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function patient()
    {
        return $this->belongsTo('App\Models\Patients', 'patients_id');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user()
    {
        return $this->belongsTo('App\Models\User', 'users_id');
    }
    
    /**
     * Relación con los pagos asociados a esta cita
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function payment()
    {
        return $this->hasOne('App\Models\Payments', 'appointment_id', 'id');
    }
    
    /**
     * Verificar si la cita tiene un pago registrado
     * @return bool
     */
    public function hasPayment()
    {
        return $this->payment()->exists();
    }

    public function getDoctor()
    {
        $doctor = UserProfile::where('users_id', $this->users_id)->first();
        return $doctor;
    }

    /**
     * 
     */
    public function createModelFromRequest($data){
        $model = [];
        $date = new DateTime();
        $data["id"] = md5($date->format('Y-m-d H:i:s'));
        foreach($data as $key =>$value){
            if(in_array($key,$this->fillable)){
                if($key === "date"){
                    $value = self::prepareDate($value);
                }
                $model[$key] = $value;
            }            
        }
        $model["code"] = "MED-".DB::table('appointments')->get()->count();
        $model["users_id"] = $data["doctorname"];
        return $model;
    }

    /**
     * 
     */
    public static function prepareDate($value){
        try {
            // Primero intentar con el formato d/m/Y h:i:s A (12 horas)
            $date = \Carbon\Carbon::createFromFormat('d/m/Y h:i:s A', $value);
            return $date;
        } catch (\Exception $e) {
            try {
                // Si falla, intentar con el formato Y-m-d H:i:s (24 horas)
                $date = date_create_from_format('Y-m-d H:i:s', $value);
                return $date;
            } catch (\Exception $e) {
                // Si ambos fallan, log del error
                \Illuminate\Support\Facades\Log::error('Error al parsear fecha: ' . $e->getMessage());
                throw $e;
            }
        }
    }

    /**
     * 
     */
    public static function getStructureFromRequest(array $data,array $extras):array{
        $appointment = [];
        $date                           = date_create_from_format('d/m/Y',$data["appointmentDate"]);
        $appointment["id"]              = md5($extras["patientsId"] . $date->format('Y-m-d H:i:s'));
        $appointment["patients_id"]     = $extras["patientsId"];
        $appointment["active"]          = 1;
        $appointment["date"]            = $date;
        $appointment["especiality"]     = $data["especiality"];
        $appointment["code"]            = "MED-". substr(md5($date->format('Y-m-d H:i:s.u')), 0, 4);
        return $appointment;
    }

    /**
     * 
     */
    public function getPhoneAppointment(){
        return (isset($this->patient()->first()->phone)) ? [$this->patient()->first()->phone] : Patients::getPhoneForRepresentatives($this->patient()->first());
    }

    /**
     * 
     */
    public function getEmailAppointment(){
        return (isset($this->patient()->first()->email)) ? [$this->patient()->first()->email] : Patients::getEmailForRepresentatives($this->patient()->first());
    }

    /**
     * 
     */
    public static function getAppointmentsMinorThat18($userId = NULL){
        $appointments = [];
        if(!isset($userId)){
            foreach(Appointments::get() as $appointment){
                if($appointment->patient->age < 18)
                     array_push($appointments,$appointment);
             }
        }else{
            foreach(Appointments::where("users_id","=",$userId)->get() as $appointment){
                if($appointment->patient->age < 18)
                     array_push($appointments,$appointment);
             }
        }
        
        return $appointments;
    }

    /**
     * 
     */
    public static function getAppointmentsMajorThat18($userId = NULL){
        $appointments = [];
        if(!isset($userId)){
            foreach(Appointments::get() as $appointment){
            if($appointment->patient->age > 17)
                    array_push($appointments,$appointment);
            }
        }else{
            foreach(Appointments::where("users_id","=",$userId)->get() as $appointment){
                if($appointment->patient->age > 17)
                     array_push($appointments,$appointment);
             }
        }
        return $appointments;
    }

    /**
     * Relación con el horario del doctor
     */
    public function doctorSchedule()
    {
        return $this->belongsTo(DoctorSchedule::class, 'doctor_id', 'doctor_id')
            ->where('day_of_week', function($query) {
                $query->selectRaw('DAYOFWEEK(appointments.date) - 1');
            });
    }

    /**
     * Validar si la cita está dentro del horario del doctor
     */
    public function validateDoctorSchedule()
    {
        $appointmentDate = Carbon::parse($this->date);
        
        $schedule = DoctorSchedule::where('doctor_id', $this->doctor_id)
            ->where('day_of_week', $appointmentDate->dayOfWeek)
            ->where('active', true)
            ->first();

        if (!$schedule) {
            return false;
        }

        // Convertir la hora de la cita a la zona horaria del doctor
        $appointmentTime = $appointmentDate->setTimezone($schedule->timezone);
        
        return $schedule->isWithinSchedule($appointmentTime);
    }

    /**
     * Verificar disponibilidad del doctor para una fecha y hora específica
     */
    public static function isDoctorAvailable($doctorId, $dateTime)
    {
        $date = Carbon::parse($dateTime);
        
        \Log::info("Verificando disponibilidad en modelo Appointments para doctor ID: $doctorId");
        \Log::info("Fecha a verificar: " . $date->format('Y-m-d H:i:s'));
        \Log::info("Día de la semana: " . $date->dayOfWeek);
        
        // Verificar si existe un horario para ese día
        $schedule = DoctorSchedule::where('doctor_id', $doctorId)
            ->where('day_of_week', $date->dayOfWeek)
            ->where('active', true)
            ->first();

        if (!$schedule) {
            \Log::info("No se encontró horario para este día");
            return false;
        }
        
        \Log::info("Horario encontrado - ID: " . $schedule->id);
        \Log::info("Horario - Inicio: " . $schedule->start_time . " - Fin: " . $schedule->end_time);

        // Verificar si la hora está dentro del horario
        $result = $schedule->isWithinSchedule($date);
        \Log::info("Resultado de isWithinSchedule: " . ($result ? "Disponible" : "No disponible"));
        
        return $result;
    }

    public function especiality()
    {
        return $this->belongsTo(Especiality::class, 'especiality', 'id');
    }
    
    /**
     * Las etiquetas que pertenecen a la cita
     * 
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
     */
    public function tags()
    {
        return $this->belongsToMany(AppointmentTag::class, 'appointment_appointment_tag', 'appointment_id', 'appointment_tag_id');
    }
}
