<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Str;
use Illuminate\Contracts\Auth\CanResetPassword;


class User extends Authenticatable implements MustVerifyEmail, CanResetPassword
{
    /** @use HasFactory<\Database\Factories\UserFactory> */
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected ?bool $profileComplete = null;
    protected $fillable = [
        'name',
        'email',
        'password',
        'otp_login_enabled',
        'referral_code',
        'referral_id',
        'visibility_level',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
            'otp_login_enabled' => 'boolean',
        ];
    }

    // User.php
    // ===== Relationships ==== //

    public function taxRefund()
    {
        return $this->hasOne(TaxRefund::class);
    }
    public function beneficiaries()
    {
        return $this->hasMany(Beneficiary::class);
    }

    public function grant()
    {
        return $this->hasOne(Grant::class);
    }

    public function grantLogs()
    {
        return $this->hasMany(GrantLog::class);
    }

    public function onboardingAudit()
    {
        return $this->hasOne(OnboardingAudit::class);
    }

    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
    public function emails()
    {
        return $this->hasMany(UserEmail::class);
    }

    public function referrer()
    {
        return $this->belongsTo(User::class, 'referral_id');
    }

    public function referrals()
    {
        return $this->hasMany(User::class, 'referral_id');
    }
    public function referralEarnings(): float
    {
        if (!$this->profile)
            return 0;

        return DB::table('transactions')
            ->join('accounts', 'transactions.account_id', '=', 'accounts.id')
            ->whereIn('accounts.id', $this->profile->accounts()->pluck('id'))
            ->where('transactions.type', 'referral_bonus')
            ->sum('transactions.amount');
    }

    public function trustedDevices()
    {
        return $this->hasMany(TrustedDevice::class);
    }
    public function userlogins()
    {
        return $this->hasMany(UserLogin::class);
    }
    public function creditcards()
    {
        return $this->hasMany(CreditCard::class);
    }
    public function kyc()
    {
        return $this->hasMany(Kyc::class);
    }
    public function tickets()
    {
        return $this->hasMany(Ticket::class);
    }
    public function messages()
    {
        return $this->hasMany(TicketMessages::class);
    }
    public function accounts()
    {
        return $this->hasManyThrough(
            \App\Models\Account::class, // final model
            \App\Models\Profile::class, // intermediate model
            'user_id', // foreign key on Profile pointing to User
            'profile_id', // foreign key on Account pointing to Profile
            'id', // local key on User
            'id'  // local key on Profile
        );
    }

    public function getKycStatusAttribute(): string
    {
        $latestKyc = Kyc::latestForUser($this->id)->first();

        return $latestKyc?->status ?? Kyc::STATUS_PENDING;
    }


    public function isProfileComplete(): bool
    {
        $profile = $this->profile;

        $missing = [];

        if (!$profile) {
            Log::info("User {$this->id} profile is missing.");
            return false;
        }
        if (empty($profile->phone))
            $missing[] = 'phone';
        if (empty($profile->dial_code))
            $missing[] = 'dial_code';
        if (empty($profile->date_of_birth))
            $missing[] = 'date_of_birth';
        if (empty($profile->address_1))
            $missing[] = 'address_1';
        if (empty($profile->occupation))
            $missing[] = 'occupation';
        if (empty($profile->gender))
            $missing[] = 'gender';
        if (empty($profile->marital_status))
            $missing[] = 'marital_status';
        if (empty($profile->country))
            $missing[] = 'country';
        if (empty($profile->state))
            $missing[] = 'state';
        if (empty($profile->city))
            $missing[] = 'city';
        if (empty($profile->zip_code))
            $missing[] = 'zip_code';
        if (empty($profile->status))
            $missing[] = 'status';
        if (empty($profile->agreement_accepted))
            $missing[] = 'agreement_accepted';

        if (!empty($missing)) {
            Log::info("User {$this->id} profile incomplete. Missing: " . implode(', ', $missing));
            return false;
        }

        return true;
    }

    protected $cascadeDeletes = [
        'profile',
        'kyc',
        'trustedDevices',
        'userlogins',
        'tickets',
        'beneficiaries',
        'grant',
        'grantLogs',
        'creditcards',
        'emails',
    ];


    protected static function booted()
    {
        static::deleting(function ($user) {
            foreach ($user->cascadeDeletes as $relationName) {
                try {
                    $relation = $user->$relationName();

                    if ($relation instanceof Relation) {
                        // BelongsToMany → detach
                        if ($relation instanceof \Illuminate\Database\Eloquent\Relations\BelongsToMany) {
                            $relation->detach();
                        }
                        // All other relations → delete related models
                        else {
                            $relation->get()->each(fn($item) => $item->delete());
                        }
                    }
                } catch (\Throwable $e) {
                    // Ignore if the relation does not exist or is misconfigured
                    continue;
                }
            }
        });

        // Keep the referral code generator on creating
        static::creating(function ($user) {
            if (empty($user->referral_code)) {
                $user->referral_code = self::generateUniqueReferralCode();
            }
        });
    }
    public function scopeVisibleToAdmin($query, Admin $admin)
    {
        if ($admin->isSuperAdmin()) {
            return $query;
        }

        if ($admin->isAdmin()) {
            return $query->where('visibility_level', '<=', 1);
        }

        return $query->whereRaw('1 = 0'); // deny completely
    }

    private static function generateUniqueReferralCode(int $length = 10): string
    {
        do {
            // You can customize this generator as needed (uppercase alphanum)
            $code = strtoupper(Str::random($length));
        } while (self::referralCodeExists($code));

        return $code;
    }

    private static function referralCodeExists(string $code): bool
    {
        return self::where('referral_code', $code)->exists();
    }
    /**
     * Get the user's initials
     */
    public function initials(): string
    {
        return Str::of($this->name)
            ->explode(' ')
            ->take(2)
            ->map(fn($word) => Str::substr($word, 0, 1))
            ->implode('');
    }

    /**
     * Check if OTP login is enabled for this user
     */
    public function otpEnabled(): bool
    {
        return $this->otp_login_enabled;
    }

    public function hasActiveTrustedDevices(): bool
    {
        return $this->trustedDevices()
            ->where('last_used_at', '>', now()->subDays(7))
            ->exists();
    }

    /**
     * Check if the user's latest KYC is verified
     */
    public function getKycVerifiedAttribute(): bool
    {
        $latestKyc = Kyc::latestForUser($this->id)->first();

        return $latestKyc?->isVerified() ?? false;
    }
    public function getVisibilityLabelAttribute(): string
    {
        return match ($this->visibility_level) {
            0 => 'Normal User',
            1 => 'Admin Only',
            2 => 'Super Admin Only',
            default => 'Unknown',
        };
    }

}
