<?php

namespace App\Models;

use App\Notifications\ResetPassword;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'username',
        'role',
        'two_factor_enabled',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
        ];
    }

    /**
     * Check if user is admin
     */
    public function isAdmin(): bool
    {
        return $this->role === 'admin';
    }

    /**
     * Check if user is petugas
     */
    public function isPetugas(): bool
    {
        return $this->role === 'petugas';
    }

    /**
     * Check if user is dokter
     */
    public function isDokter(): bool
    {
        return $this->role === 'dokter';
    }

    /**
     * Relasi ke Dokter (One to One)
     * Satu user bisa menjadi satu dokter
     */
    public function dokter()
    {
        return $this->hasOne(Dokter::class, 'user_id');
    }

    /**
     * Relasi ke Pasien yang didaftarkan oleh user ini
     */
    public function pasienYangDidaftarkan()
    {
        return $this->hasMany(Pasien::class, 'didaftarkan_oleh');
    }
    /**
     * Relasi ke Pemeriksaan Kesehatan yang dilakukan user
     */
    public function pemeriksaanKesehatan()
    {
        return $this->hasMany(PemeriksaanKesehatan::class, 'diperiksa_oleh');
    }

    /**
     * Relasi ke Embedding Wajah yang didaftarkan user
     */
    public function embeddingWajahYangDidaftarkan()
    {
        return $this->hasMany(EmbeddingWajah::class, 'didaftarkan_oleh');
    }

    /**
     * Relasi ke Analisis AI yang diminta user
     */
    public function analisisAi()
    {
        return $this->hasMany(AnalisisAi::class, 'diminta_oleh');
    }

    /**
     * Relasi ke Log Notifikasi yang dikirim user
     */
    public function notifikasiYangDikirim()
    {
        return $this->hasMany(LogNotifikasi::class, 'dikirim_oleh');
    }

    /**
     * Relasi ke Pengaturan Sistem yang diubah user
     */
    public function pengaturanSistemYangDiubah()
    {
        return $this->hasMany(PengaturanSistem::class, 'diubah_oleh');
    }

    /**
     * Relasi ke Log Aktivitas Sistem
     */
    public function logAktivitas()
    {
        return $this->hasMany(LogAktivitasSistem::class);
    }

    /**
     * Relasi ke Dokter yang didaftarkan user
     */
    public function dokterYangDidaftarkan()
    {
        return $this->hasMany(Dokter::class, 'didaftarkan_oleh');
    }

    /**
     * Relasi ke Dokter-Pasien yang didaftarkan user
     */
    public function dokterPasienYangDidaftarkan()
    {
        return $this->hasMany(DokterPasien::class, 'didaftarkan_oleh');
    }

    /**
     * Scope untuk filter berdasarkan role
     */
    public function scopeRole($query, $role)
    {
        return $query->where('role', $role);
    }

    /**
     * Scope untuk admin
     */
    public function scopeAdmin($query)
    {
        return $query->where('role', 'admin');
    }

    /**
     * Scope untuk petugas
     */
    public function scopePetugas($query)
    {
        return $query->where('role', 'petugas');
    }

    /**
     * Scope untuk dokter
     */
    public function scopeDokter($query)
    {
        return $query->where('role', 'dokter');
    }

    /**
     * Get role label untuk display
     */
    public function getRoleLabelAttribute(): string
    {
        return match($this->role) {
            'admin' => 'Administrator',
            'petugas' => 'Petugas Kesehatan',
            'dokter' => 'Dokter',
            default => 'Unknown'
        };
    }

    /**
     * Get initials from name
     */
    public function getInitialsAttribute(): string
    {
        $words = explode(' ', $this->name);
        if (count($words) >= 2) {
            return strtoupper(substr($words[0], 0, 1) . substr($words[1], 0, 1));
        }
        return strtoupper(substr($this->name, 0, 2));
    }

    /**
     * Relasi ke Two Factor Codes
     */
    public function twoFactorCodes()
    {
        return $this->hasMany(TwoFactorCode::class);
    }

    /**
     * Send the password reset notification.
     */
    public function sendPasswordResetNotification($token): void
    {
        $this->notify(new ResetPassword($token));
    }

    /**
     * Get current OTP code untuk user ini
     */
    public function getCurrentTwoFactorCode(): ?TwoFactorCode
    {
        return $this->twoFactorCodes()
            ->where('expires_at', '>', now())
            ->first();
    }

    /**
     * Check apakah email sudah diverifikasi
     */
    public function isEmailVerified(): bool
    {
        return $this->email_verified_at !== null;
    }

    /**
     * Generate OTP code dan kirim via email
     */
    public function generateAndSendOtpCode(): TwoFactorCode
    {
        $otp = TwoFactorCode::createForUser($this);
        
        // Kirim email dengan OTP
        $this->notify(new \App\Notifications\SendOtpCode($otp));
        
        return $otp;
    }

    /**
     * Verify OTP code
     */
    public function verifyOtpCode(string $code): bool
    {
        $otp = $this->getCurrentTwoFactorCode();

        if (!$otp) {
            return false;
        }

        if ($otp->isLocked()) {
            return false;
        }

        if ($otp->code === $code) {
            // OTP benar - tandai email sebagai verified
            $this->update(['email_verified_at' => now()]);
            $otp->delete();
            return true;
        }

        // OTP salah - increment attempts
        $otp->incrementAttempts();
        return false;
    }

    /**
     * Get available roles
     */
    public static function getRoles(): array
    {
        return [
            'admin' => 'Administrator',
            'petugas' => 'Petugas Kesehatan',
            'dokter' => 'Dokter',
        ];
    }
}