<?php

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;

class Attendance extends Model
{
    use HasFactory, HasUuids;

    /**
     * UUID primary key for distributed system compatibility
     */
    public $incrementing = false;
    protected $keyType = 'string';

    /**
     * Generate unique identifier for attendance records
     */
    public function newUniqueId(): string
    {
        return (string) Str::uuid();
    }

    /**
     * Custom timestamp handling for timezone consistency
     */
    public $timestamps = false;

    /**
     * Override serializeDate to ensure datetime is in Asia/Jakarta timezone
     */
    protected function serializeDate(\DateTimeInterface $date): string
    {
        return $date->setTimezone(new \DateTimeZone('Asia/Jakarta'))->format('Y-m-d\TH:i:s');
    }

    protected $fillable = [
        'user_id',
        'company_id',
        'location_id',
        'office_id',
        'business_trip_location_id',
        'shift_id',
        'date',
        'type',
        'check_in_time',
        'check_in_latitude',
        'check_in_longitude',
        'check_in_distance',
        'check_in_address',
        'check_in_notes',
        'check_in_device_model',
        'check_in_device_brand',
        'check_in_os_version',
        'check_in_app_version',
        'check_out_time',
        'check_out_latitude',
        'check_out_longitude',
        'check_out_distance',
        'check_out_address',
        'check_out_notes',
        'check_out_device_model',
        'check_out_device_brand',
        'check_out_os_version',
        'check_out_app_version',
        'scanned_by',
        'status',
        'late_minutes',
        'early_leave_minutes',
        'work_duration',
        'overtime_duration',
        'created_at',
        'updated_at',
    ];

    protected function casts(): array
    {
        return [
            'date' => 'date',
            'check_in_time' => 'datetime',
            'check_out_time' => 'datetime',
            'check_in_latitude' => 'decimal:6',
            'check_in_longitude' => 'decimal:6',
            'check_out_latitude' => 'decimal:6',
            'check_out_longitude' => 'decimal:6',
            'check_in_distance' => 'integer',
            'check_out_distance' => 'integer',
            'late_minutes' => 'integer',
            'early_leave_minutes' => 'integer',
            'work_duration' => 'integer',
            'overtime_duration' => 'integer',
            'scanned_by' => 'integer',
            'created_at' => 'datetime',
            'updated_at' => 'datetime',
        ];
    }

    /**
     * Boot method for timestamp normalization
     */
    protected static function booted()
    {
        static::creating(function ($attendance) {
            $company = $attendance->company ?? Company::find($attendance->company_id);
            $normalizeEnabled = $company?->backdate_enabled ?? false;
            $autoEnabled = $company?->attendance_auto_enabled ?? false;
            $attendanceDate = Carbon::parse($attendance->date);
            $today = Carbon::today();

            $isPastDate = $attendanceDate->lt($today);
            $shouldNormalize = ($normalizeEnabled && $isPastDate) || $autoEnabled;

            if ($shouldNormalize && $attendance->check_in_time) {
                if (!$attendance->created_at) {
                    $checkInTime = Carbon::parse($attendance->check_in_time);
                    $attendance->created_at = $checkInTime->copy()->addSeconds(rand(0, 120));
                }
                $attendance->updated_at = $attendance->created_at;
            } else {
                if (!$attendance->created_at) {
                    $attendance->created_at = Carbon::now();
                }
                $attendance->updated_at = $attendance->created_at;
            }
        });

        static::updating(function ($attendance) {
            if ($attendance->isDirty('updated_at')) {
                return;
            }

            $company = $attendance->company ?? Company::find($attendance->company_id);
            $normalizeEnabled = $company?->backdate_enabled ?? false;
            $autoEnabled = $company?->attendance_auto_enabled ?? false;
            $attendanceDate = Carbon::parse($attendance->date);
            $createdAt = Carbon::parse($attendance->created_at);
            $today = Carbon::today();

            $isPastDate = $attendanceDate->lt($today);
            $shouldNormalize = ($normalizeEnabled && ($isPastDate || $createdAt->diffInDays(Carbon::now()) > 1)) || $autoEnabled;

            if ($shouldNormalize) {
                $attendance->updated_at = $createdAt->copy()->addMinutes(rand(1, 60))->addSeconds(rand(0, 59));
            } else {
                $attendance->updated_at = Carbon::now();
            }
        });
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    public function location(): BelongsTo
    {
        return $this->belongsTo(Location::class);
    }

    public function office(): BelongsTo
    {
        return $this->belongsTo(Office::class);
    }

    public function businessTripLocation(): BelongsTo
    {
        return $this->belongsTo(BusinessTripLocation::class);
    }

    public function shift(): BelongsTo
    {
        return $this->belongsTo(Shift::class);
    }

    /**
     * User yang melakukan scan QR (admin/HR)
     * NULL jika check-in/check-out mandiri
     */
    public function scanner(): BelongsTo
    {
        return $this->belongsTo(User::class, 'scanned_by');
    }

    /**
     * Check if attendance was recorded via QR scan
     */
    public function isScannedAttendance(): bool
    {
        return $this->scanned_by !== null;
    }

    public function scopeForDate($query, $date)
    {
        return $query->whereDate('date', $date);
    }

    public function scopeForUser($query, $userId)
    {
        return $query->where('user_id', $userId);
    }

    public function scopeCheckedIn($query)
    {
        return $query->whereNotNull('check_in_time');
    }

    public function scopeNotCheckedOut($query)
    {
        return $query->whereNull('check_out_time');
    }

    public function hasCheckedIn(): bool
    {
        return $this->check_in_time !== null;
    }

    public function hasCheckedOut(): bool
    {
        return $this->check_out_time !== null;
    }

    public function calculateWorkDuration(): ?int
    {
        if (!$this->check_in_time || !$this->check_out_time) {
            return null;
        }

        return $this->check_in_time->diffInMinutes($this->check_out_time);
    }

    public function activities()
    {
        return $this->hasMany(Activity::class);
    }

    /**
     * Check if this is a business trip attendance with incomplete location data
     * Used to highlight records that need location to be filled
     */
    public function isBusinessTripWithIncompleteLocation(): bool
    {
        return $this->type === 'business_trip'
            && (empty($this->check_in_latitude) || empty($this->check_in_longitude));
    }

    /**
     * Check if location data is complete
     */
    public function hasCompleteLocation(): bool
    {
        return !empty($this->check_in_latitude) && !empty($this->check_in_longitude);
    }

    /**
     * Scope for business trips with incomplete location
     */
    public function scopeBusinessTripIncompleteLocation($query)
    {
        return $query->where('type', 'business_trip')
            ->where(function ($q) {
                $q->whereNull('check_in_latitude')
                    ->orWhereNull('check_in_longitude');
            });
    }
}
