<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Auth;
use OwenIt\Auditing\Contracts\Auditable;
use OwenIt\Auditing\Auditable as AuditableTrait;
use Illuminate\Support\Str;
use Carbon\Carbon;

class Employee extends Model implements Auditable
{
    use HasFactory, SoftDeletes, AuditableTrait;

    protected $guarded =[
        'deleted_at'
    ];

    protected $casts = [
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    public function employee_profile(): BelongsTo
    {
        return $this->belongsTo(EmployeeProfilePicture::class, 'employee_id', 'employee_id');
    }

    public function section(): BelongsTo
    {
        return $this->belongsTo(Section::class, 'section_id');
    }

    public function position(): BelongsTo
    {
        return $this->belongsTo(JobTitle::class, 'position_id');
    }

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

    public function chargeTo(): BelongsTo
    {
        return $this->belongsTo(Company::class, 'charge_to');
    }

    public function classification(): BelongsTo
    {
        return $this->belongsTo(JobClassification::class, 'classification_id');
    }

    public function dealership(): BelongsTo
    {
        return $this->belongsTo(Dealership::class, 'dealer_id');
    }

    public function salary_grade(): BelongsTo
    {
        return $this->belongsTo(SalaryGrade::class, 'job_grade_id');
    }

    public function employment_type(): BelongsTo
    {
        return $this->belongsTo(EmploymentType::class, 'employment_status_id');
    }

    public function group(): BelongsTo
    {
        return $this->belongsTo(Group::class, 'group_id');
    }

    public function division(): BelongsTo
    {
        return $this->belongsTo(Division::class, 'division_id');
    }

    public function department(): BelongsTo
    {
        return $this->belongsTo(Department::class, 'department_id');
    }

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

    public function locality(): BelongsTo
    {
        return $this->belongsTo(Locality::class, 'work_location_id');
    }

    public function salary_and_wages(): BelongsTo
    {
        return $this->belongsTo(SalaryAndWages::class, 'employee_id', 'employee_id');
    }

    public function passport(): BelongsTo
    {
        return $this->belongsTo(Passport::class, 'employee_id', 'employee_id');
    }

    public function personal_information(): BelongsTo
    {
        return $this->belongsTo(PersonalInformation::class, 'employee_id', 'employee_id');
    }

    public function paf(): HasMany
    {
        return $this->hasMany(PersonnelActionForm::class, 'employee_id', 'employee_id');
    }

    public function audit(): HasMany
    {
        return $this->hasMany(Audit::class, 'user_id', 'id');
    }

    public function device_registration(): HasMany
    {
        return $this->hasMany(DeviceRegistration::class, 'employee_id');
    }

    public function timelog(): HasMany
    {
        return $this->hasMany(Timelog::class, 'employee_id', 'employee_id');
    }

    // Approvers
    public function unitApprover(): BelongsTo
    {
        return $this->belongsTo(Approver::class, 'unit_id', 'type_id');
    }

    public function sectionApprover(): BelongsTo
    {
        return $this->belongsTo(Approver::class, 'section_id', 'type_id');
    }

    public function departmentApprover(): BelongsTo
    {
        return $this->belongsTo(Approver::class, 'department_id', 'type_id');
    }

    public function divisionApprover(): BelongsTo
    {
        return $this->belongsTo(Approver::class, 'division_id', 'type_id');
    }

    public function groupDivisionApprover(): BelongsTo
    {
        return $this->belongsTo(Approver::class, 'group_id', 'type_id');
    }

    public function dealershipApprover(): BelongsTo
    {
        return $this->belongsTo(Approver::class, 'dealer_id', 'type_id');
    }

    // Accessor for First Name
    public function getFirstnameAttribute($value)
    {
        return Str::title(Str::lower($value));
    }

    // Accessor for Middle Name
    public function getMiddlenameAttribute($value)
    {
        return Str::title(Str::lower($value));
    }

    // Accessor for Last Name
    public function getLastnameAttribute($value)
    {
        return Str::title(Str::lower($value));
    }

    public function recommendedEmployees(): BelongsToMany
    {
        return $this->belongsToMany(
            Employee::class,  // Related model
            'employee_approvers', // Pivot table
            'signatory_id',  // This employee (who is the recommender)
            'employee_id'    // The recommended employee
        )->withPivot(['attendance_type', 'attendance_id', 'is_approver']);
    }

    // Employees who recommended this employee
    public function recommenders(): BelongsToMany
    {
        return $this->belongsToMany(
            Employee::class,
            'employee_approvers',
            'employee_id', // The employee being recommended
            'signatory_id' // The employee who recommended
        )->withPivot(['attendance_type', 'attendance_id', 'is_approver']);
    }

     public function processed_absences(): HasMany
    {
        return $this->hasMany(ProcessedAbsent::class, 'employee_id');
    }

    public function processed_schedules(): HasMany
    {
        return $this->hasMany(ProcessedSchedule::class, 'employee_id');
    }

      public function attendanceData()
    {
        return $this->hasOne(ProcessedSchedule::class, 'employee_id')
            ->selectRaw('employee_id,
                SUM(CASE WHEN restday = 0 AND holiday IS NULL THEN 1 ELSE 0 END) as workdays')
            ->groupBy('employee_id');
    }

     // --- STATIC HELPER TO INCLUDE ATTENDANCE IN QUERY ---
    /**
     * Return a Collection of employees with an attached `attendance_percentage` attribute.
     *
     * @param string|null $start YYYY-MM-DD or any Carbon-parseable string. Defaults to start of current month.
     * @param string|null $end   YYYY-MM-DD or any Carbon-parseable string. Defaults to end of current month.
     * @return \Illuminate\Support\Collection
     */
    public static function withAttendancePercentage($start = null, $end = null)
    {
        // Global range used for eager loading (to limit DB results)
        $globalStart = $start ? Carbon::parse($start)->startOfDay() : now()->startOfMonth()->startOfDay();
        $globalEnd   = $end   ? Carbon::parse($end)->endOfDay()       : now()->endOfMonth()->endOfDay();

        // Eager load schedules and absences but restrict them to the global range
        $employees = self::with([
            'processed_absences' => function ($q) use ($globalStart, $globalEnd) {
                $q->whereBetween('date', [$globalStart->toDateString(), $globalEnd->toDateString()]);
            },
            'processed_schedules' => function ($q) use ($globalStart, $globalEnd) {
                $q->whereBetween('date', [$globalStart->toDateString(), $globalEnd->toDateString()]);
            }
        ])->get();

        // Compute attendance per employee respecting their individual start/resign dates
        return $employees->map(function ($employee) use ($globalStart, $globalEnd) {
            // Effective start: later of globalStart and employee.date_started
            $empStart = $employee->date_hired
                ? Carbon::parse($employee->date_hired)->startOfDay()
                : $globalStart;

            if ($empStart->lessThan($globalStart)) {
                $empStart = $globalStart->copy();
            }

            // Effective end: earlier of globalEnd and employee.date_resigned (if any)
            $empEnd = $employee->date_resign
                ? Carbon::parse($employee->date_resign)->endOfDay()
                : $globalEnd;

            if ($empEnd->greaterThan($globalEnd)) {
                $empEnd = $globalEnd->copy();
            }

            // If employee resigned before the global start or started after global end => no period
            if ($empEnd->lt($empStart)) {
                $employee->attendance_percentage = 0;
                return $employee;
            }

            // Count workdays from the already-loaded schedules, but filter them per-employee date range
            $workdays = $employee->processed_schedules
                ->filter(function ($s) use ($empStart, $empEnd) {
                    // ensure schedule date is within the employee effective period
                    $d = Carbon::parse($s->date);
                    return $d->betweenIncluded($empStart, $empEnd)
                        && (int)$s->restday === 0
                        && is_null($s->holiday);
                })
                ->count();

            // Count absences within the employee effective period
            $absences = $employee->processed_absences
                ->filter(function ($a) use ($empStart, $empEnd) {
                    $d = Carbon::parse($a->date);
                    return $d->betweenIncluded($empStart, $empEnd);
                })
                ->count();

            $employee->attendance_percentage = $workdays > 0
                ? round(100 - (($absences / $workdays) * 100), 2)
                : 0;

            // Optionally attach the effective start/end for debugging / frontend use:
            $employee->attendance_period = [
                'from' => $empStart->toDateString(),
                'to'   => $empEnd->toDateString(),
                'workdays' => $workdays,
                'absences' => $absences,
            ];

            return $employee;
        });
    }


}
