<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, HasRoles;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'phone',
        'bvn',
        'last_login_at',
        'last_activity_at',
        'password',
        'transaction_pin',
        'transaction_pin_set_at',
        'terms_accepted_version',
        'terms_accepted_at',
        'customer_tier',
        'status',
        'is_banned',
        'banned_services_json',
        'ban_reason',
        'banned_at',
        'referral_code',
        'referred_by_user_id',
    ];

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

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'bvn' => 'encrypted',
        'last_login_at' => 'datetime',
        'last_activity_at' => 'datetime',
        'password' => 'hashed',
        'transaction_pin' => 'hashed',
        'transaction_pin_set_at' => 'datetime',
        'terms_accepted_at' => 'datetime',
        'is_banned' => 'boolean',
        'banned_services_json' => 'array',
        'banned_at' => 'datetime',
    ];

    public const CUSTOMER_TIERS = ['subscriber', 'reseller', 'agent'];
    public const STATUSES = ['active', 'suspended'];
    public const BAN_SERVICE_KEYS = ['data', 'airtime', 'cable', 'electricity', 'epin', 'wallet_transfer', 'wallet_funding'];

    public function wallet(): HasOne
    {
        return $this->hasOne(Wallet::class);
    }

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

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

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

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

    public function referrer(): BelongsTo
    {
        return $this->belongsTo(self::class, 'referred_by_user_id');
    }

    public function referralsMade(): HasMany
    {
        return $this->hasMany(Referral::class, 'referrer_user_id');
    }

    public function referralRecord(): HasOne
    {
        return $this->hasOne(Referral::class, 'referred_user_id');
    }

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

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

    public function cashbackWallet(): HasOne
    {
        return $this->hasOne(CashbackWallet::class);
    }

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

    public function sentWalletTransfers(): HasMany
    {
        return $this->hasMany(WalletTransfer::class, 'sender_user_id');
    }

    public function receivedWalletTransfers(): HasMany
    {
        return $this->hasMany(WalletTransfer::class, 'recipient_user_id');
    }

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

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

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

    public function adminAuditLogs(): HasMany
    {
        return $this->hasMany(AdminAuditLog::class, 'admin_id');
    }

    public function inactivityFeeRunsInitiated(): HasMany
    {
        return $this->hasMany(InactivityFeeRun::class, 'initiated_by_admin_id');
    }

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

    public function isActiveCustomer(): bool
    {
        return ($this->status ?? 'active') === 'active' && ! $this->is_banned;
    }

    public function bannedServices(): array
    {
        return array_values(array_unique(array_map('strval', (array) ($this->banned_services_json ?? []))));
    }

    public function hasTransactionPin(): bool
    {
        return filled($this->transaction_pin);
    }

    public function verifyTransactionPin(string $pin): bool
    {
        if (! $this->hasTransactionPin()) {
            return false;
        }

        return Hash::check($pin, (string) $this->transaction_pin);
    }

    public function setTransactionPin(string $pin): void
    {
        $this->transaction_pin = $pin;
        $this->transaction_pin_set_at = now();
    }
}
