<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

/**
 * TrainingAttendance Model
 *
 * Tracks attendance for each training session per registered participant.
 *
 * @property int $id
 * @property int $training_session_id
 * @property int $user_id
 * @property int|null $registration_id
 * @property string $attendance_status
 * @property \Illuminate\Support\Carbon|null $check_in_time
 * @property \Illuminate\Support\Carbon|null $check_out_time
 * @property int|null $duration_minutes
 * @property int|null $checked_in_by
 * @property int|null $checked_out_by
 * @property string|null $notes
 * @property string|null $absence_reason
 * @property float|null $latitude
 * @property float|null $longitude
 * @property string|null $ip_address
 * @property string|null $user_agent
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 */
class TrainingAttendance extends Model
{
    use HasFactory;

    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'training_attendance';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'training_session_id',
        'user_id',
        'registration_id',
        'attendance_status',
        'check_in_time',
        'check_out_time',
        'duration_minutes',
        'checked_in_by',
        'checked_out_by',
        'notes',
        'absence_reason',
        'latitude',
        'longitude',
        'ip_address',
        'user_agent',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'check_in_time' => 'datetime',
        'check_out_time' => 'datetime',
        'duration_minutes' => 'integer',
        'latitude' => 'decimal:8',
        'longitude' => 'decimal:8',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    /**
     * The model's default values for attributes.
     *
     * @var array
     */
    protected $attributes = [
        'attendance_status' => 'pending',
    ];

    // =========================================================================
    // RELATIONSHIPS
    // =========================================================================

    /**
     * Get the training session.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function trainingSession(): BelongsTo
    {
        return $this->belongsTo(TrainingSession::class, 'training_session_id');
    }

    /**
     * Get the user (attendee).
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    /**
     * Get the registration.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function registration(): BelongsTo
    {
        return $this->belongsTo(TrainingRegistration::class, 'registration_id');
    }

    /**
     * Get the user who checked this person in.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function checkInBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'checked_in_by');
    }

    /**
     * Get the user who checked this person out.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function checkOutBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'checked_out_by');
    }

    // =========================================================================
    // QUERY SCOPES
    // =========================================================================

    /**
     * Scope to get present attendees.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePresent($query)
    {
        return $query->where('attendance_status', 'present');
    }

    /**
     * Scope to get absent attendees.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeAbsent($query)
    {
        return $query->where('attendance_status', 'absent');
    }

    /**
     * Scope to get late attendees.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeLate($query)
    {
        return $query->where('attendance_status', 'late');
    }

    /**
     * Scope to get pending attendance.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePending($query)
    {
        return $query->where('attendance_status', 'pending');
    }

    /**
     * Scope to get attendance for a specific session.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param int $sessionId
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeForSession($query, int $sessionId)
    {
        return $query->where('training_session_id', $sessionId);
    }

    /**
     * Scope to get attendance for a specific user.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param int $userId
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeForUser($query, int $userId)
    {
        return $query->where('user_id', $userId);
    }

    // =========================================================================
    // HELPER METHODS
    // =========================================================================

    /**
     * Check if the attendee is present.
     *
     * @return bool
     */
    public function isPresent(): bool
    {
        return $this->attendance_status === 'present';
    }

    /**
     * Check if the attendee is absent.
     *
     * @return bool
     */
    public function isAbsent(): bool
    {
        return $this->attendance_status === 'absent';
    }

    /**
     * Check if the attendee is late.
     *
     * @return bool
     */
    public function isLate(): bool
    {
        return $this->attendance_status === 'late';
    }

    /**
     * Check if the attendance is pending.
     *
     * @return bool
     */
    public function isPending(): bool
    {
        return $this->attendance_status === 'pending';
    }

    /**
     * Check in the attendee.
     *
     * @param int|null $checkedInBy
     * @param array $location
     * @return bool
     */
    public function checkIn(?int $checkedInBy = null, array $location = []): bool
    {
        $data = [
            'attendance_status' => 'present',
            'check_in_time' => now(),
            'checked_in_by' => $checkedInBy,
        ];
        
        if (!empty($location['latitude'])) {
            $data['latitude'] = $location['latitude'];
        }
        
        if (!empty($location['longitude'])) {
            $data['longitude'] = $location['longitude'];
        }
        
        return $this->update($data);
    }

    /**
     * Check out the attendee.
     *
     * @param int|null $checkedOutBy
     * @return bool
     */
    public function checkOut(?int $checkedOutBy = null): bool
    {
        $checkOutTime = now();
        $durationMinutes = null;
        
        if ($this->check_in_time) {
            $durationMinutes = $checkOutTime->diffInMinutes($this->check_in_time);
        }
        
        return $this->update([
            'check_out_time' => $checkOutTime,
            'checked_out_by' => $checkedOutBy,
            'duration_minutes' => $durationMinutes,
        ]);
    }

    /**
     * Mark as absent.
     *
     * @param string|null $reason
     * @return bool
     */
    public function markAbsent(?string $reason = null): bool
    {
        return $this->update([
            'attendance_status' => 'absent',
            'absence_reason' => $reason,
        ]);
    }

    /**
     * Mark as late.
     *
     * @param int|null $markedBy
     * @param string|null $notes
     * @return bool
     */
    public function markLate(?int $markedBy = null, ?string $notes = null): bool
    {
        return $this->update([
            'attendance_status' => 'late',
            'check_in_time' => now(),
            'checked_in_by' => $markedBy,
            'notes' => $notes,
        ]);
    }

    /**
     * Mark as excused.
     *
     * @param string $reason
     * @return bool
     */
    public function markExcused(string $reason): bool
    {
        return $this->update([
            'attendance_status' => 'excused',
            'absence_reason' => $reason,
        ]);
    }

    /**
     * Get the attendance duration in minutes.
     *
     * @return int|null
     */
    public function getDuration(): ?int
    {
        if ($this->duration_minutes) {
            return $this->duration_minutes;
        }
        
        if ($this->check_in_time && $this->check_out_time) {
            return $this->check_out_time->diffInMinutes($this->check_in_time);
        }
        
        return null;
    }

    /**
     * Get formatted duration.
     *
     * @return string
     */
    public function getFormattedDuration(): string
    {
        $minutes = $this->getDuration();
        
        if ($minutes === null) {
            return 'N/A';
        }
        
        $hours = floor($minutes / 60);
        $mins = $minutes % 60;
        
        if ($hours > 0 && $mins > 0) {
            return "{$hours}h {$mins}m";
        } elseif ($hours > 0) {
            return "{$hours}h";
        } else {
            return "{$mins}m";
        }
    }

    /**
     * Get the status badge color for UI.
     *
     * @return string
     */
    public function getStatusBadgeColor(): string
    {
        return match($this->attendance_status) {
            'present' => 'green',
            'absent' => 'red',
            'late' => 'yellow',
            'excused' => 'blue',
            'pending' => 'gray',
            default => 'gray',
        };
    }
}
