<?php

namespace App\Models;

use App\Http\Helpers\FileUploader;
use App\Traits\HasBillingAccount;
use App\Traits\HasCurrency;
use App\Traits\HasWallet;
use App\Traits\Locationable;
use App\Traits\Phonable;
use App\Traits\Rateable;
use App\Traits\Sociable;
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\Http\UploadedFile;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Kayalous\SocialAuth\App\Http\Traits\HasSocialAuth;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;
use mysql_xdevapi\Exception;
use Overtrue\LaravelLike\Traits\Liker;
use Spatie\Permission\Traits\HasRoles;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens;
    use HasFactory;
    use HasProfilePhoto;
    use Notifiable;
    use TwoFactorAuthenticatable;
    use HasSocialAuth;
    use HasSlug;
    use Sociable;
    use Locationable;
    use Phonable;
    use Liker;
    use HasBillingAccount;
    use HasCurrency;
    use Rateable;
    use HasRoles;
    use HasWallet;
    use SoftDeletes;
    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $guarded = [];
    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array
     */

    public static function boot()
    {
        parent::boot();


        self::created(function($model){
            $model->wallet()->create();
        });
    }
    protected $hidden = [
        "password",
        "remember_token",
        "two_factor_recovery_codes",
        "two_factor_secret",
    ];
    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        "email_verified_at" => "datetime",
        "is_current_user" => "boolean",
        "is_admin" => "boolean",
        "is_engineer" => "boolean",
        "is_firm" => "boolean",
    ];
    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = [
        "profile_photo_url",
        "is_current_user",
        'averageRating',
        "is_engineer",
        "is_firm",
        "total_spent",
        "projects_count",
        'successful_jobs',
        'socials'
    ];

    public function getSlugOptions(): SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom("name")
            ->saveSlugsTo("slug")
            ->slugsShouldBeNoLongerThan(50)
            ->doNotGenerateSlugsOnUpdate();
    }

    public function engineer()
    {
        return $this->hasOne(Engineer::class);
    }

    public function stripeErrors(){
        return $this->hasMany(StripeError::class);
    }

    public function verificationRequest(){
        return $this->hasMany(VerificationRequest::class);
    }

    public function firm()
    {
        return $this->hasOne(Firm::class);
    }

    public function serviceOrders()
    {
        return $this->hasMany(ServiceOrder::class);
    }

    public function projects()
    {
        return $this->hasMany(Project::class);
    }

    public function contracts()
    {
        return $this->hasMany(Contract::class);
    }

    public function getIsCurrentUserAttribute()
    {
        return $this?->id == Auth::user()?->id;
    }

    public function getIsEngineerAttribute()
    {
        return $this->engineer()->exists();
    }

    public function getIsFirmAttribute()
    {
        return $this->firm()->exists();
    }

    public function savedServices()
    {
        $likes = $this->likes()
            ->with("likeable")
            ->withType(Service::class)
            ->get();

        $saved = [];
        foreach ($likes as $like) {
            $likeable = $like->likeable()->with(
                "images",
            "skills",
            "location",
            "tierOptions",
            "orders",
            "serviceable.user"
            )->first();

            $saved[] = json_decode($likeable);
        }
        return $saved;
    }

    public function savedProjects()
    {
        $likes = $this->likes()
            ->with("likeable")
            ->withType(Project::class)
            ->get();

        $saved = [];
        foreach ($likes as $like) {
            $likeable = $like->likeable()->with(
                "files",
                "location",
                "skills",
                "user",
                "LevelOfExperience"
            )->first();

            $saved[] = json_decode($likeable);
        }
        return $saved;
    }



    public function getSuccessfulJobsAttribute()
    {
        $count = 0;
        try {
                $count += $this->projects()->where("status", "Completed")->count();
                $count += $this->serviceOrders()->where("status", "closed")->count();
        }catch (\Exception $exception){
            dd($exception);
        }
        return $count;
    }

    public function chats()
    {
        return $this->hasMany(Chat::class);
    }

    public function approvedPayouts(){
        return $this->hasMany(PayoutRequest::class);
    }

    public function getProposalCountAttribute()
    {
        $projects = $this->projects;
        $sum = 0;
        foreach ($projects as $project) {
            $sum += $project->proposalCount;
        }
        return $sum;
    }
    public function getTotalSpentAttribute()
    {

        //return 0;
//        dd($this);
//        if($this->id == Auth::user()?->id) {
//            if ($this->engineer != null) {
//                return $this->engineer->wallet != null ? $this->engineer->wallet->total_spent : 0;
//            } else if ($this->firm != null) {
//                return $this->firm->wallet != null ? $this->firm->wallet->total_spent : 0;
//            }
//        }
        return $this->wallet!=null? $this->wallet->total_spent : 0;
    }
    public function getProjectsCountAttribute()
    {
        return $this->projects()->count();
    }


    public function getProcessingProjectsCountAttribute()
    {
        return $this->projects()->where('status','Processing')->count();
    }
    public function services(){
        $orders = $this->serviceOrders()->orderBy('created_at','desc')->paginate(5)->getCollection();
        $services = [];
        foreach ($orders as $order){
            $service = $order->service->load('images',
            'skills',
            'location',
            'tierOptions',
            'orders',
            'serviceable.user',
            'serviceable.currency',
            );
            $service->active_order_id = $order->id;
            $service->active_order_status = $order->status;
            $services[] = $service;

        }
        return $services;
    }

    public function getActiveOrdersCountAttribute(){

        return $this->serviceOrders()->where('status', 'in progress')->count();
    }
    /**
     * Update the user's profile photo.
     *
     * @param  \Illuminate\Http\UploadedFile  $photo
     * @return void
     */
    public function updateProfilePhoto(UploadedFile $photo)
    {
        tap($this->profile_photo_path, function ($previous) use ($photo) {
            $this->forceFill([
                'profile_photo_path' => FileUploader::store('profile-photos/', $photo),
            ])->save();

            if ($previous) {
                Storage::disk($this->profilePhotoDisk())->delete($previous);
            }
        });
    }
    public function updateCoverPhoto(UploadedFile $photo)
    {
        tap($this->profile_photo_path, function ($previous) use ($photo) {
            $this->forceFill([
                'cover_photo_path' => FileUploader::store('profile-photos/', $photo),
            ])->save();

            if ($previous) {
                Storage::disk($this->profilePhotoDisk())->delete($previous);
            }
        });
    }

    /**
     * Get the URL to the user's profile photo.
     *
     * @return string
     */
    public function getProfilePhotoUrlAttribute()
    {
        // dd($this->profile_photo_path);
        return $this->profile_photo_path
                    ? $this->profile_photo_path
                    : $this->defaultProfilePhotoUrl();
    }

    public function getAllNotificationsAttribute()
    {
        // check if user is engineer or firm
        $notifications = [];
        // add user notifications to array
        $notifications = array_merge($notifications, $this->notifications()->get()->toArray());
        // add engineer notifications to array
        if ($this->engineer) {
            $notifications = array_merge($notifications, $this->engineer->notifications()->get()->toArray());
        }
        // add firm notifications to array
        if ($this->firm) {
            $notifications = array_merge($notifications, $this->firm->notifications()->get()->toArray());
        }
        // sort notifications by created_at
        usort($notifications, function ($a, $b) {
            return $a['created_at'] <=> $b['created_at'];
        });
        // reverse array
        $notifications = array_reverse($notifications);

        return $notifications;
    }

    public function clearAllNotifications(){
        // // set read_at to now
        $this->notifications()->update(['read_at' => now()]);
        //  set read_at to now for engineer notifications
        if ($this->engineer) {
            $this->engineer->notifications()->update(['read_at' => now()]);
        }
         // set read_at to now for firm notifications
        if ($this->firm) {
            $this->firm->notifications()->update(['read_at' => now()]);
        }

    }

    public function getUnreadMessageCountAttribute() {
        $unread = 0;
        if($this->is_engineer) {
            $unread += $this->engineer->getUnreadMessageCountAttribute();
        }
        if($this->is_firm) {
            $unread += $this->firm->getUnreadMessageCountAttribute();
        }
        foreach ($this->chats as $chat) {
            $unread += $chat->messages()->where('sender_uid', '!=', $this->id)->where('read_at', null)->count();
        }
        if($unread > 99) return 99;
        return $unread;
    }
}
