<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
 * StaffHistory Model
 *
 * Represents an employment record for a staff member.
 * Tracks employment dates, status, position, and achievements.
 *
 * @property int $id
 * @property int $organization_id
 * @property int|null $user_id
 * @property string $staff_name
 * @property string $position
 * @property \Illuminate\Support\Carbon $employment_start_date
 * @property \Illuminate\Support\Carbon|null $employment_end_date
 * @property string $employment_status
 * @property string|null $termination_reason
 * @property string|null $passport_path
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @property \Illuminate\Support\Carbon|null $deleted_at
 */
class StaffHistory extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * Employment status constants.
     */
    const STATUS_CURRENT = 'current';
    const STATUS_FORMER = 'former';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'organization_id',
        'user_id',
        'staff_name',
        'position',
        'employment_start_date',
        'employment_end_date',
        'employment_status',
        'termination_reason',
        'passport_path',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'employment_start_date' => 'date',
        'employment_end_date' => 'date',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    /**
     * The "booted" method of the model.
     */
    protected static function booted(): void
    {
        static::saving(function (StaffHistory $staff) {
            // Ensure employment status consistency
            if ($staff->employment_end_date) {
                $staff->employment_status = self::STATUS_FORMER;
            } elseif ($staff->employment_status === self::STATUS_CURRENT) {
                $staff->employment_end_date = null;
            }
        });
    }

    /**
     * Get the organization for this staff record.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function organization()
    {
        return $this->belongsTo(Organization::class);
    }

    /**
     * Get the user associated with this staff record.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Get the achievements for this staff record.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function achievements()
    {
        return $this->hasMany(StaffAchievement::class);
    }

    /**
     * Add an achievement to this staff record.
     *
     * @param string $description
     * @param string $date
     * @return StaffAchievement
     */
    public function addAchievement(string $description, string $date): StaffAchievement
    {
        return $this->achievements()->create([
            'achievement_description' => $description,
            'achievement_date' => $date,
        ]);
    }

    /**
     * End this staff member's employment.
     *
     * @param string $endDate
     * @param string|null $reason
     * @return bool
     */
    public function endEmployment(string $endDate, ?string $reason = null): bool
    {
        $this->employment_end_date = $endDate;
        $this->employment_status = self::STATUS_FORMER;
        $this->termination_reason = $reason;
        return $this->save();
    }

    /**
     * Get the employment duration in days.
     *
     * @return int|null
     */
    public function getEmploymentDurationInDays(): ?int
    {
        $endDate = $this->employment_end_date ?? now();
        return $this->employment_start_date->diffInDays($endDate);
    }

    /**
     * Get the employment duration in a human-readable format.
     *
     * @return string
     */
    public function getEmploymentDurationAttribute(): string
    {
        $endDate = $this->employment_end_date ?? now();
        return $this->employment_start_date->diffForHumans($endDate, true);
    }

    /**
     * Check if this staff member is currently employed.
     *
     * @return bool
     */
    public function isCurrent(): bool
    {
        return $this->employment_status === self::STATUS_CURRENT;
    }

    /**
     * Check if this staff member is a former employee.
     *
     * @return bool
     */
    public function isFormer(): bool
    {
        return $this->employment_status === self::STATUS_FORMER;
    }

    /**
     * Get the status label.
     *
     * @return string
     */
    public function getStatusLabelAttribute(): string
    {
        return ucfirst($this->employment_status);
    }

    /**
     * Scope to get only current staff.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeCurrent($query)
    {
        return $query->where('employment_status', self::STATUS_CURRENT);
    }

    /**
     * Scope to get only former staff.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeFormer($query)
    {
        return $query->where('employment_status', self::STATUS_FORMER);
    }

    /**
     * Scope to filter by organization.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param int $organizationId
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeForOrganization($query, int $organizationId)
    {
        return $query->where('organization_id', $organizationId);
    }

    /**
     * Scope to filter by position.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $position
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeByPosition($query, string $position)
    {
        return $query->where('position', 'like', "%{$position}%");
    }

    /**
     * Scope to filter by date range.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $startDate
     * @param string $endDate
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeDateRange($query, string $startDate, string $endDate)
    {
        return $query->where(function ($q) use ($startDate, $endDate) {
            $q->whereBetween('employment_start_date', [$startDate, $endDate])
                ->orWhereBetween('employment_end_date', [$startDate, $endDate]);
        });
    }

    /**
     * Scope to search by staff name or position.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $search
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeSearch($query, string $search)
    {
        return $query->where(function ($q) use ($search) {
            $q->where('staff_name', 'like', "%{$search}%")
                ->orWhere('position', 'like', "%{$search}%");
        });
    }

    /**
     * Scope to order by employment start date.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $direction
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeOrderByStartDate($query, string $direction = 'desc')
    {
        return $query->orderBy('employment_start_date', $direction);
    }

    /**
     * Get the passport URL for display or download.
     *
     * @return string|null
     */
    public function getPassportUrl(): ?string
    {
        if (!$this->passport_path) {
            return null;
        }

        return \Illuminate\Support\Facades\Storage::disk('public')->url($this->passport_path);
    }

    /**
     * Check if staff member has a passport file.
     *
     * @return bool
     */
    public function hasPassport(): bool
    {
        return !is_null($this->passport_path) && \Illuminate\Support\Facades\Storage::disk('public')->exists($this->passport_path);
    }

    /**
     * Delete the passport file from storage.
     *
     * @return bool
     */
    public function deletePassport(): bool
    {
        if (!$this->passport_path) {
            return false;
        }

        if (\Illuminate\Support\Facades\Storage::disk('public')->exists($this->passport_path)) {
            \Illuminate\Support\Facades\Storage::disk('public')->delete($this->passport_path);
        }

        $this->passport_path = null;
        return $this->save();
    }

    /**
     * The "deleting" event handler.
     */
    protected static function booting(): void
    {
        parent::booting();

        static::deleting(function (StaffHistory $staff) {
            // Delete passport file when record is deleted
            if ($staff->passport_path && \Illuminate\Support\Facades\Storage::disk('public')->exists($staff->passport_path)) {
                \Illuminate\Support\Facades\Storage::disk('public')->delete($staff->passport_path);
            }
        });
    }
}
