<?php

namespace App\Models;

use App\Enums\EmailAndTelephoneTypeEnum;
use App\Http\Controllers\Api\Platform\StorageFileController;
use App\Notifications\CommunityMemberShipStatusNotification;
use App\Notifications\SendDisputeInvitationNotification;
use App\Notifications\SendDisputeMessageNotification;
use App\Notifications\SendRealtimeMessageNotification;
use App\Services\UserService;
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\Facades\Hash;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
   use HasApiTokens, HasFactory, Notifiable, SoftDeletes;
   use UserService;

   static string $prefixDir = "user_";

   /**
    * The database table used by the model.
    *
    * @var string
    */
   protected $table = 'users';

   /**
    * Attributes that should be mass-assignable.
    *
    * @var array
    */
   protected $fillable = [
      'email',
      'telephone',
      'user_name',
      'bio',
      'verification_requested_at',
      'verified_at',
      'declined_at',
      'blocked_at',
      'profile_picture',
      'user_type',
      'password',
      'language_code',

      'user_detail_id',
      'country_id'
   ];

   /**
    * The attributes excluded from the model's JSON form.
    *
    * @var array
    */
   protected $hidden = [
      'password',
      'user_detail_id',
      'country_id'
   ];

   /**
    * The attributes that should be casted to native types.
    *
    * @var array
    */
   protected $casts = [
      'validated_at' => 'datetime',
      'declined_at' => 'datetime',
      'blocked_at' => 'datetime',
      'verified_at' => 'datetime',
      'verification_requested_at' => 'datetime',
   ];

   /**
    * The attributes that should be mutated to dates.
    *
    * @var array
    */
   protected $dates = [
      'created_at',
      'updated_at',
      'deleted_at',
      'verification_requested_at',
      'blocked_at',
      'verified_at'
   ];

   /**
    * The accessors to append to the model's array form.
    *
    * @var array
    */
   protected $appends = ['avatar', 'verification_status', 'user_attributes', 'profile_url'];

   /**  Append attributes */

   public function getUserAttributesAttribute(): ?array
   {
      return null;
   }

   public function getAvatarAttribute(): ?string
   {
      return $this->computeAvatarLink();
   }

   /**
    * Compute avatar url
    *
    * @return string|null
    */
   public function computeAvatarLink(): ?string
   {
      if (filled($this->{'profile_picture'})) {
         return build_storage_file_url($this, StorageFileController::userAvatarFlag, $this->{'profile_picture'});
      }

      return null;
   }

   /**
    * @return string
    */
   public function getProfileUrlAttribute(): string
   {
      return $this->buildUserProfileUrl();
   }

   /**
    * Build user profile url
    *
    * @return string
    */
   public function buildUserProfileUrl(): string
   {
      return build_user_profile_url($this->{"id"});
   }

   public function getVerificationStatusAttribute(): ?string
   {
      $lastVerification = $this->userVerificationStatus();

      return $lastVerification?->{'status'};
   }

   /**
    * The "booting" method of the model.
    *
    * @return void
    */
   public static function boot(): void
   {
      parent::boot();
   }

   /** Attributes used outside the class to create modify the resource */

   /**
    * Creation attributes
    *
    * @return string[]
    */
   public static function creationAttributes(): array
   {
      return [
         'telephone',
         'user_name',
         'profile_picture',
         'password',
         'country_code'
      ];
   }

   /** Others methods */

   /**
    * Verify password
    *
    * @param string $plainTextPassword
    * @return bool
    */
   public function verifyPassword(string $plainTextPassword): bool
   {
      return Hash::check($plainTextPassword, $this->{'password'});
   }

   /**
    * User small name
    *
    * @return string
    */
   public function smallName(): string
   {
      return sprintf(
         '%s %s',
         explode(' ', single_space($this->{'userDetail'}->{'last_name'}))[0],
         explode(' ', single_space($this->{'userDetail'}->{'first_name'}))[0],
      );
   }

   public function fullName(): string
   {
      return sprintf(
         '%s %s',
         $this->{'userDetail'}->{'last_name'},
         $this->{'userDetail'}->{'first_name'},
      );
   }

   /** One signal  */

   /**
    * In order to let your Notification know which OneSignal user(s)
    * you are targeting, add the
    *
    * @return array[]
    */
   public function routeNotificationForOneSignal(): array
   {
      return [
         'tags' => [
            'key' => 'user_id',
            'relation' => '=',
            'value' => '' . $this->{'id'}
         ]
      ];
   }

   /**
    * Send one signal notification for new chat message
    *
    * @param array $message
    * @return void
    */
   public function notifyForNewChatMessage(array $message): void
   {
      $this->notify(new SendRealtimeMessageNotification($message));
   }

   /**
    * Send one signal notification for new dispute invitation
    *
    * @param Dispute $dispute
    * @return void
    */
   public function notifyForDisputeInvitation(Dispute $dispute): void
   {
      $this->notify(new SendDisputeInvitationNotification($dispute));
   }

   /**
    * Send one signal notification for new dispute message
    *
    * @param array $message
    * @return void
    */
   public function notifyForNewDisputeMessage(array $message): void
   {
      $this->notify(new SendDisputeMessageNotification($message));
   }

   /**
    * Send community membership status notification
    *
    * @param CommunityMembershipRequest $membershipRequest
    * @return void
    */
   public function notifyForCommunityMemberShipStatus(CommunityMembershipRequest $membershipRequest): void
   {
      $this->notify(new CommunityMemberShipStatusNotification($membershipRequest));
   }

   /** Relations */

   public function userDetail(): \Illuminate\Database\Eloquent\Relations\BelongsTo
   {
      return $this->belongsTo(UserDetail::class, 'user_detail_id');
   }

   public function userDevice(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(UserDevice::class, 'user_id');
   }

   public function business(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(Business::class, 'owner_user_id');
   }

   public function wallet(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(Wallet::class);
   }

   public function country(): \Illuminate\Database\Eloquent\Relations\BelongsTo
   {
      return $this->belongsTo(Country::class);
   }

   public function userInterest(): \Illuminate\Database\Eloquent\Relations\BelongsToMany
   {
      return $this->belongsToMany(User::class, "user_interests", "user_id", "business_sub_category_id");
   }

   public function userPrimaryNumber(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(UserTelephone::class)->where("type", EmailAndTelephoneTypeEnum::primary->value)->whereNull("deactivated_at");
   }

   public function userTelephones(): \Illuminate\Database\Eloquent\Relations\HasMany
   {
      return $this->hasMany(UserTelephone::class);
   }

   public function userPrimaryEmail(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(UserEmail::class)->where("type", EmailAndTelephoneTypeEnum::primary->value)->whereNull("deactivated_at");
   }

   public function userEmails(): \Illuminate\Database\Eloquent\Relations\HasMany
   {
      return $this->hasMany(UserEmail::class);
   }

   public function userPasswordChangeHistory(): \Illuminate\Database\Eloquent\Relations\HasMany
   {
      return $this->hasMany(PasswordChangeHistory::class);
   }

   public function otpVerifications(): \Illuminate\Database\Eloquent\Relations\HasMany
   {
      return $this->hasMany(OtpVerification::class);
   }

   public function accountPrivacySetting(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(AccountPrivacySetting::class);
   }

   public function accountNotificationSetting(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(AccountNotificationSetting::class);
   }

   public function userSearch(): \Illuminate\Database\Eloquent\Relations\HasMany
   {
      return $this->hasMany(SearchHistory::class);
   }

   public function userFollower(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(Follower::class, 'follower_user_id');
   }

   public function userFollowing(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(Follower::class, 'following_user_id');
   }

   public function participant(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(RealtimeParticipant::class, 'participant_id', 'id');
   }

   public function disputeParticipant(): \Illuminate\Database\Eloquent\Relations\HasOne
   {
      return $this->hasOne(DisputeParticipant::class, 'participant_id', 'id');
   }
}
