<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Str;
use App\Models\Result;
use App\Models\ResultApproval;
use App\Models\AnnualResultApproval;
use App\Models\Announcement;
use App\Models\Setting;
use Illuminate\Support\Facades\Cache;

class User extends Authenticatable
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory, Notifiable, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'firstname',
        'middlename',
        'surname',
        'email',
        'username',
        'phone',
        'student_id',
        'gender',
        'marital_status',
        'address',
        'dob',
        'place_of_birth',
        'profile_photo',
        'country_id',
        'state_id',
        'city_id',
        'previous_school',
        'previous_class',
        'admission_date',
        'nok_name',
        'nok_phone',
        'nok_relationship',
        'nok_address',
        'official_remarks',
        'password',
        'batch_id',
        'active',
        'monthly_salary',
        'bank_name',
        'account_number',
        'account_name',
        'tax_id',
        'payment_day',
        'meta',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<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',
            'monthly_salary' => 'decimal:0',
            'meta' => 'array',
        ];
    }

    /**
     * Get the user's full name
     */
    public function getNameAttribute(): string
    {
        return trim($this->firstname . ' ' . ($this->middlename ? $this->middlename . ' ' : '') . $this->surname);
    }

    /**
     * Get first name in Title Case
     */
    public function getFirstnameAttribute($value)
    {
        return Str::title($value);
    }

    /**
     * Get middle name in Title Case
     */
    public function getMiddlenameAttribute($value)
    {
        return $value ? Str::title($value) : $value;
    }

    /**
     * Get surname in Title Case
     */
    public function getSurnameAttribute($value)
    {
        return Str::title($value);
    }

    /**
     * Get the user's initials
     */
    public function initials(): string
    {
        return Str::of($this->name)
            ->explode(' ')
            ->take(2)
            ->map(fn($word) => Str::substr($word, 0, 1))
            ->implode('');
    }

    /**
     * Roles relationship
     */
    public function roles()
    {
        return $this->belongsToMany(Role::class, 'user_roles');
    }

    /**
     * Check if user has a specific role
     */
    public function hasRole($role)
    {
        return $this->roles()->where('name', $role)->exists();
    }

    /**
     * Check if user has any of the given roles
     */
    public function hasAnyRole($roles)
    {
        return $this->roles()->whereIn('name', (array)$roles)->exists();
    }

    /**
     * Check if user has all of the given roles
     */
    public function hasAllRoles($roles)
    {
        $roles = (array)$roles;
        return $this->roles()->whereIn('name', $roles)->count() === count($roles);
    }

    /**
     * Check if user has a specific permission
     */
    public function hasPermission($permission)
    {
        return $this->roles()->get()->some(function ($role) use ($permission) {
            return $role->hasPermission($permission);
        });
    }

    /**
     * Role check methods
     */
    public function isAdmin()
    {
        return $this->hasRole('admin');
    }

    public function isBursar()
    {
        return $this->hasRole('bursar');
    }

    public function isHeadTeacher()
    {
        return $this->hasRole('head_teacher');
    }

    public function isTeacher()
    {
        return $this->hasRole('teacher');
    }

    public function isStudent()
    {
        return $this->roles()->count() === 0;
    }

    /**
     * Batch relationship
     */
    public function batch()
    {
        return $this->belongsTo(Batch::class);
    }

    /**
     * Classes relationship (for teachers)
     */
    public function classes()
    {
        return $this->belongsToMany(SchoolClass::class, 'teacher_classes');
    }

    /**
     * Country relationship
     */
    public function country()
    {
        return $this->belongsTo(Country::class);
    }

    /**
     * State relationship
     */
    public function state()
    {
        return $this->belongsTo(State::class);
    }

    /**
     * City relationship
     */
    public function city()
    {
        return $this->belongsTo(City::class);
    }

    /**
     * School class relationship through batch (for students)
     */
    public function schoolClass()
    {
        return $this->hasOneThrough(SchoolClass::class, Batch::class, 'id', 'id', 'batch_id', 'school_class_id');
    }

    /**
     * Results relationship (for students)
     */
    public function results()
    {
        return $this->hasMany(Result::class, 'student_id');
    }

    /**
     * Result approvals relationship (for students)
     */
    public function resultApprovals()
    {
        return $this->hasMany(ResultApproval::class, 'student_id');
    }

    /**
     * Annual result approvals relationship (for students)
     */
    public function annualResultApprovals()
    {
        return $this->hasMany(AnnualResultApproval::class, 'student_id');
    }

    public function payments()
    {
        return $this->hasMany(Payment::class);
    }

    /**
     * Payment requests relationship (for students)
     */
    public function paymentRequests()
    {
        return $this->hasMany(PaymentRequest::class, 'student_id');
    }

    /**
     * Created payment requests relationship (for staff)
     */
    public function createdPaymentRequests()
    {
        return $this->hasMany(PaymentRequest::class, 'created_by');
    }

    /**
     * Created announcements relationship (for staff)
     */
    public function createdAnnouncements()
    {
        return $this->hasMany(Announcement::class, 'created_by');
    }

    /**
     * Dismissed announcements relationship
     */
    public function dismissedAnnouncements()
    {
        return $this->belongsToMany(Announcement::class, 'announcement_dismissals')
            ->withTimestamps();
    }

    /**
     * Check if user can approve results based on settings
     */
    public function canApproveResults()
    {
        if ($this->isAdmin()) {
            return Setting::get('allow_admin_approve_results', true);
        }

        if ($this->isHeadTeacher()) {
            return Setting::get('allow_head_teacher_approve_results', true);
        }

        if ($this->isTeacher()) {
            return Setting::get('allow_teacher_approve_results', false);
        }

        return false;
    }

    /**
     * Salary histories relationship
     */
    public function salaryHistories()
    {
        return $this->hasMany(SalaryHistory::class);
    }

    /**
     * Get latest salary history
     */
    public function latestSalaryHistory()
    {
        return $this->hasOne(SalaryHistory::class)->latest();
    }

    /**
     * Check if user is staff (has payroll access)
     */
    public function isStaff()
    {
        return $this->hasAnyRole(['admin', 'bursar', 'head_teacher', 'teacher', 'driver', 'security', 'cleaner']);
    }

    /**
     * Boot method to handle model events
     */
    protected static function boot()
    {
        parent::boot();

        static::created(function ($user) {
            self::clearDashboardCache();
        });

        static::updated(function ($user) {
            self::clearDashboardCache();
        });

        static::deleted(function ($user) {
            self::clearDashboardCache();
        });
    }

    /**
     * Clear dashboard related cache
     */
    public static function clearDashboardCache()
    {
        Cache::forget('total_students_count');
        Cache::forget('total_staff_count');
        Cache::forget('total_classes_count');
        
        // Clear teacher-specific caches
        $teachers = User::whereHas('roles', function($query) {
            $query->where('name', 'teacher');
        })->pluck('id');
        
        foreach ($teachers as $teacherId) {
            Cache::forget("teacher_students_count_{$teacherId}");
            Cache::forget("teacher_classes_count_{$teacherId}");
        }
    }
}
