<?php

namespace App\Models;

use App\Models\Branch;
use App\Models\Role\Role;
use App\Models\Notification;
use App\Models\Role\RoleUser;
use Laravel\Cashier\Billable;
use App\Models\Hrm\Appreciate;
use App\Models\Company\Company;
use App\Models\Hrm\Shift\Shift;
use App\Models\Hrm\Notice\Notice;
use App\Models\Track\LocationLog;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Activitylog\LogOptions;
use App\Models\Hrm\Country\Country;
use App\Models\Payroll\SalarySetup;
use App\Models\Hrm\Leave\DailyLeave;
use App\Models\Hrm\Leave\AssignLeave;
use App\Models\Payroll\AdvanceSalary;
use App\Models\Settings\LocationBind;
use App\Models\Hrm\Leave\LeaveRequest;
use App\Models\Payroll\SalaryGenerate;
use Illuminate\Support\Facades\Schema;
use App\Models\ActivityLogs\AuthorInfo;
use Modules\Tardy\Entities\TardyRecord;
use Illuminate\Notifications\Notifiable;
use Modules\Tardy\Entities\TardyRequest;
use App\Models\Hrm\Attendance\Attendance;
use App\Models\Hrm\Department\Department;
use App\Models\Hrm\Support\SupportTicket;
use App\Models\coreApp\Setting\UserIpBind;
use App\Models\Payroll\SalarySetupDetails;
use App\Models\Hrm\Designation\Designation;
use Modules\Tardy\Entities\TardyRuleAssign;
use Spatie\Activitylog\Traits\LogsActivity;
use App\Models\coreApp\Setting\CompanyConfig;
use App\Models\coreApp\Social\SocialIdentity;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\SpecialAttendance\Entities\Deduction;
use Illuminate\Database\Eloquent\Relations\HasOne;
use GPBMetadata\Google\Firestore\Admin\V1\Location;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Modules\SpecialAttendance\Entities\DutyCalendar;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Models\coreApp\Traits\Relationship\StatusRelationTrait;
use App\Models\Hrm\Attendance\DutySchedule;

class User extends Authenticatable
{
    use HasApiTokens,
        HasFactory,
        Notifiable,
        SoftDeletes,
        StatusRelationTrait,
        LogsActivity,
        Billable;

    protected $guarded = ['id'];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];
    protected $appends = array();
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'permissions' => 'array',
        'weekends' => 'array',
        'company_id' => 'integer',
        'attendance_method' => 'json',
    ];

    protected static $logAttributes = [
        'company_id',
        'name',
        'phone',
        'email',
        'role_id',
        'department_id',
        'designation_id',
        'permissions',
        'password',
        'avatar_id',
        'status_id',
        'device_token',
        'address',
        'gender',
        'birth_date',
        'religion',
        'blood_group',
        'joining_date',
        'basic_salary',
        'marital_status',
        'employee_id',
        'passport_number',
        'passport_file_id',
        'bank_name',
        'bank_account',
        'manager_id',
        'employee_type',
        'branch_id',
    ];

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

    public function deActiveCompany(): BelongsTo
    {
        return $this->belongsTo(Company::class, 'company_id', 'id')->where('status_id', '!=', 1)->withDefault();
    }

    public function branch(): BelongsTo
    {
        return $this->belongsTo(Branch::class, 'branch_id', 'id')->withDefault();
    }

    public function companyConfigs(): HasMany
    {
        return $this->hasMany(CompanyConfig::class, 'company_id', 'company_id');
    }

    public function country(): BelongsTo
    {
        return $this->belongsTo(Country::class, 'country_id')->withDefault();
    }

    public function identities(): HasMany
    {
        return $this->hasMany(SocialIdentity::class);
    }

    public function uploads(): HasMany
    {
        return $this->hasMany(Upload::class);
    }

    //can be common relationship make it trait
    public function author(): BelongsTo
    {
        return $this->belongsTo(AuthorInfo::class, 'id', 'authorable_id');
    }

    public function allAuthor(): HasMany
    {
        return $this->hasMany(AuthorInfo::class, 'created_by', 'id');
    }

    public function roleUser(): HasOne
    {
        return $this->hasOne(RoleUser::class, 'user_id', 'id');
    }

    public function userRole(): BelongsTo
    {
        return $this->belongsTo(RoleUser::class, 'user_id', 'id');
    }

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

    public function designation(): BelongsTo
    {
        return $this->belongsTo(Designation::class, 'designation_id', 'id');
    }

    public function role(): BelongsTo
    {
        return $this->belongsTo(Role::class, 'role_id', 'id');
    }

    public function manager(): BelongsTo
    {
        return $this->belongsTo(User::class, 'manager_id');
    }

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

    public function Leave(): HasMany
    {
        return $this->hasMany(AssignLeave::class, 'department_id', 'department_id');
    }

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


    public function notices(): HasMany
    {
        return $this->hasMany(Notice::class, 'department_id', 'id');
    }

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

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

    public function myHr()
    {
        $hr_info = $this->where('is_hr', 1)->where('company_id', auth()->user()->company_id)->first();
        if ($hr_info) {
            return $hr_info;
        } else {
            $admin_info = $this->where('is_admin', 1)->where('company_id', auth()->user()->company_id)->first();
            if ($admin_info) {
                return $admin_info;
            } else {
                return null;
            }
        }
    }

    public function myTeam()
    {
        return $this->where('manager_id', auth()->user()->id)->get();
    }

    public function unreadNoticeNotifications()
    {
        return $this->hasMany(Notification::class, 'notifiable_id', 'id')->where('notification_for', 'notice')->where('read_at', null);
    }

    public function unreadNotifications()
    {
        return $this->hasMany(Notification::class, 'notifiable_id', 'id')->whereNull('read_at');
    }

    public function allNotifications()
    {
        return $this->hasMany(Notification::class, 'notifiable_id', 'id');
    }

    public function salary_setup()
    {
        return $this->hasOne(SalarySetup::class, 'user_id', 'id');
    }

    public function staffCommissions()
    {
        return $this->hasMany(SalarySetupDetails::class, 'user_id', 'id');
    }

    public function location_log()
    {
        return $this->hasOne(LocationLog::class, 'user_id', 'id')->orderBy('id', 'desc');
    }


    public function all_shifts()
    {
        return $this->belongsToMany(Shift::class, 'user_shift_assigns');
    }

    protected static function boot()
    {
        parent::boot();
        if (!app()->runningInConsole() && auth()->check() && !config('app.single_db')) {
            static::creating(function ($model) {
                $model->branch_id = userBranch();
                $model->employee_id = 'EMP-' . $model->id;
                $model->permissions = $model->role->permissions;
                $model->is_hr = $model->role->slug == 'hr' ? 1 : 0;
            });
        }
    }

    public function notification_channels()
    {
        $notification_channels = [
            'user' . $this->id . str_replace(' ', '', auth()->user()->company->name),
            'department' . $this->department_id . str_replace(' ', '', auth()->user()->company->name),
            'company' . auth()->user()->company->id . str_replace(' ', '', auth()->user()->company->name),
        ];
        return $notification_channels;
    }

    public function notification_subscribe_channel()
    {
        $notification_channels = [
            'user' . $this->id . 'company' . $this->company_id,
            'department' . $this->department_id . 'company' . $this->company_id,
            'company' . $this->company_id,
        ];

        return $notification_channels;
    }


    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults();
    }

    public function scopeActive($query)
    {
        return $query->where('users.status_id', '=', 1);
        //1,2,3,33,34
    }

    // User.php

    public function staffMembers()
    {
        return $this->hasMany(User::class, 'manager_id', 'id');
    }

    // default shift fetch
    public function default_shift()
    {
        return $this->hasOne(UserShiftAssign::class, 'user_id', 'id');
    }

    public function shifts()
    {
        return $this->hasMany(UserShiftAssign::class, 'user_id', 'id');
    }

    public function dutySchedule()
    {
        return $this->belongsTo(DutySchedule::class, 'duty_calendar_id', 'id');
    }

    public function lastDutyCalendar()
    {
        return $this->hasOne(DutyCalendar::class, 'employee_id', 'id')->orderByDesc('date');
    }

    public function ipBind(): HasOne
    {
        return $this->hasOne(UserIpBind::class, 'user_id', 'id');
    }

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

    public function deductions()
    {
        return $this->hasMany(Deduction::class, 'user_id', 'id');
    }

    public function salaryGenerates()
    {
        return $this->hasMany(SalaryGenerate::class, 'user_id', 'id');
    }

    public function tardyRecords()
    {
        return $this->hasMany(TardyRecord::class, 'user_id', 'id');
    }

    public function tardyRequests()
    {
        return $this->hasMany(TardyRequest::class, 'user_id', 'id');
    }

    public function dailyLeaves()
    {
        return $this->hasMany(DailyLeave::class, 'user_id', 'id');
    }

    public function advanceSalaries()
    {
        return $this->hasMany(AdvanceSalary::class, 'user_id', 'id');
    }

    public function supportTickets()
    {
        return $this->hasMany(SupportTicket::class, 'user_id', 'id');
    }

    public function hrUserIds($user)
    {
        return $this->where([
            'is_hr' => 1,
            'company_id' => $user->company_id,
            'branch_id' => $user->branch_id,
            'status_id' => 1,
        ])
            ->pluck('id')
            ->toArray();
    }

    public function scopeAuthorizable($query)
    {
        $query->when(Schema::hasColumn($this->getTable(), 'company_id'), function ($q) {
            $q->where('company_id', auth()->user()->company_id);
        })->when(Schema::hasColumn($this->getTable(), 'branch_id'), function ($q) {
            $q->where('branch_id', auth()->user()->branch_id);
        });
    }

    public function leaveRequests()
    {
        return $this->hasMany(LeaveRequest::class, 'user_id', 'id');
    }
}
