<?php

namespace App\Models;

use App\Models\Locations\Location;
use App\Models\User;
use App\Notifications\NonUserPasswordResetNotification;
use App\Notifications\VerifyProfileEmail;
use App\Traits\ActiveStatesTrait;
use App\Traits\HasPresence;
use App\Traits\LocationTrait;
use App\Traits\TaggableWithLocale;
use Illuminate\Auth\MustVerifyEmail as AuthMustVerifyEmail;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Storage;
use Laravel\Jetstream\HasProfilePhoto;
use Namu\WireChat\Traits\Chatable;
use Spatie\Activitylog\LogOptions;
use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\Permission\Traits\HasRoles;

class Admin extends Authenticatable implements MustVerifyEmail, CanResetPasswordContract
{
    use HasFactory;
    use AuthMustVerifyEmail;
    use Notifiable;
    use HasRoles;
    use LogsActivity; // Spatie Activity Log
    use HasProfilePhoto;
    use TaggableWithLocale;
    use LocationTrait;
    use CanResetPassword; // Trait
    use Chatable;
    use ActiveStatesTrait;
    use HasPresence;

    /**
     * The attributes that should be hidden for serialization.
     * BEWARE: API's CAN POTENTIALLY EXPOSE ALL VISIBLE FIELDS
     *
     * @var array
     */
    protected $hidden = [
        'email',
        'email_verified_at',
        'full_name',
        'password',
        'remember_token',
        'phone',
        'cyclos_id',
        'cyclos_salt',
        'two_factor_confirmed_at',
        'two_factor_recovery_codes',
        'two_factor_secret',
        'limit_min',
        'limit_max',
        'lang_preference',
        'created_at',
        'updated_at',
        'last_login_at',
        'inactive_at',
        'deleted_at',
    ];

    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $fillable = [
        'name',
        'full_name',
        'email',
        'profile_photo_path',
        'about',
        'about_short',
        'motivation',
        'website',
        'phone',
        'phone_public',
        'password',
        'limit_min',
        'limit_max',
        'lang_preference',
        'last_login_at',
        'last_login_ip'
    ];


    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'phone_public' => 'boolean',
        'email_verified_at' => 'datetime',
        'inactive_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];


    /**
     * Get the admin's user(s) that can manage admin profiles.
     * Many-to-many.
     */
    public function users()
    {
        return $this->belongsToMany(User::class);
    }


    /**
     * Get all related languages of the admin.
     * Many-to-many polymorphic.
     */
    public function languages()
    {
        return $this->morphToMany(Language::class, 'languagable')->withPivot('competence');
    }


    /**
     * Get all related the locations of the admin.
     * One-to-many polymorph.
     */
    public function locations()
    {
        return $this->morphMany(Location::class, 'locatable');
    }


    /**
     * Get all related accounts of the user.
     * One-to-many polymorphic.
     * NOTE: At the moment admins do not use accounts, but to keep methods consistent
     * with the other profile models, we keep this method.
     * Removing this method will break generic methods that will are used on all profile models!
     */
    public function accounts()
    {
        return $this->morphMany(Account::class, 'accountable');
    }

    /**
     * Get all of the admin's message settings.
     */
    public function message_settings()
    {
        return $this->morphMany(MessageSetting::class, 'message_settingable');
    }


    public function sendEmailVerificationNotification()
    {
        \Mail::to($this->email)->send(new \App\Mail\VerifyProfileEmailMailable($this));
    }

    /**
     * Send the password reset notification.
     *
     * @param  string  $token
     * @return void
     */
    public function sendPasswordResetNotification($token)
    {
        // Construct the full reset URL using the named route
        // The route 'non-user.password.reset' expects 'profileType' and 'token' parameters.
        // It's also good practice to include the email in the query string for the reset form.
        $resetUrl = route('non-user.password.reset', [
            'profileType' => 'admin', // Hardcode 'admin' for the Admin model
            'token' => $token,
            'email' => $this->getEmailForPasswordReset(), // Method from CanResetPassword trait
        ]);

        // Pass the fully constructed URL to your notification
        $this->notify(new NonUserPasswordResetNotification($resetUrl, $this));
    }


    /**
     * Configure the activity log options for the User model.
     *
     * This method sets up the logging to:
     * - Only log changes to the 'name', 'password', and 'last_login_ip' attributes.
     * - Log only when these attributes have been modified (dirty).
     * - Prevent submission of empty logs.
     * - Use 'user' as the log name.
     *
     * @return \Spatie\Activitylog\LogOptions
     */
    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->logOnly([
                'name',
                'last_login_ip',
                'inactive_at',
                'deleted_at',
            ])
            ->logOnlyDirty()   // Only log attributes that have been changed
            ->dontSubmitEmptyLogs()
            ->useLogName('Admin');
    }


    /**
    * Wirechat: Returns the URL for the user's cover image (avatar).
    * Adjust the 'avatar_url' field to your database setup.
    */
    public function getCoverUrlAttribute(): ?string
    {
        return Storage::url($this->profile_photo_path) ?? null;
    }


    /**
    * Wirechat:Returns the URL for the user's profile page.
    * Adjust the 'profile' route as needed for your setup.
    */
    public function getProfileUrlAttribute(): ?string
    {
        return route('profile.show_by_type_and_id', ['type' => __('admin'), 'id' => $this->id]);
    }


    /**
    * Wirechat: Returns the display name for the user.
    * Modify this to use your preferred name field.
    */
    public function getDisplayNameAttribute(): ?string
    {
        if ($this->full_name !== $this->name) {
            return $this->full_name . ' (' . $this->name . ')';
        } elseif ($this->name) {
            return $this->name;
        } else {
            return __('Admin');
        }
    }


    /**
    * Wirechat: Search for users when creating a new chat or adding members to a group.
    * Customize the search logic to limit results, such as restricting to friends or eligible users only.
    */
    public function searchChatables(string $query): ?\Illuminate\Support\Collection
    {
        $searchableFields = ['name', 'full_name'];

        // Search across all profile types
        $users = \App\Models\User::where(function ($queryBuilder) use ($searchableFields, $query) {
            foreach ($searchableFields as $field) {
                $queryBuilder->orWhere($field, 'LIKE', '%'.$query.'%');
            }
        })->limit(6)->get();

        $organizations = \App\Models\Organization::where(function ($queryBuilder) use ($searchableFields, $query) {
            foreach ($searchableFields as $field) {
                $queryBuilder->orWhere($field, 'LIKE', '%'.$query.'%');
            }
        })->limit(6)->get();

        $banks = \App\Models\Bank::where(function ($queryBuilder) use ($searchableFields, $query) {
            foreach ($searchableFields as $field) {
                $queryBuilder->orWhere($field, 'LIKE', '%'.$query.'%');
            }
        })->limit(6)->get();

        $admins = Admin::where(function ($queryBuilder) use ($searchableFields, $query) {
            foreach ($searchableFields as $field) {
                $queryBuilder->orWhere($field, 'LIKE', '%'.$query.'%');
            }
        })->limit(6)->get();

        // Combine all results into a base Collection to avoid serialization issues
        $results = collect()
            ->merge($users->all())
            ->merge($organizations->all())
            ->merge($banks->all())
            ->merge($admins->all());

        // Filter out profiles based on configuration
        return $results->filter(function ($profile) {
            // Check inactive profiles
            if (timebank_config('profile_inactive.messenger_hidden') && !$profile->isActive()) {
                return false;
            }

            // Check email unverified profiles
            if (timebank_config('profile_email_unverified.messenger_hidden') && !$profile->isEmailVerified()) {
                return false;
            }

            // Check incomplete profiles
            if (
                timebank_config('profile_incomplete.messenger_hidden')
                && method_exists($profile, 'hasIncompleteProfile')
                && $profile->hasIncompleteProfile($profile)
            ) {
                return false;
            }

            return true;
        })->take(6)->values();
    }


    /**
    * Wirechat: Determine if the user can create new groups.
    */
    public function canCreateGroups(): bool
    {
        return  timebank_config('profiles.bank.messenger_can_create_groups');
    }
}
