<?php

namespace App\Models;

use App\Notifications\VerifyEmailCode;
use Database\Factories\UserFactory;
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;
use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
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;

#[Fillable([
    'plan_id',
    'name',
    'email',
    'email_verified_at',
    'email_verification_code',
    'email_verification_code_expires_at',
    'password',
    'role',
    'status',
    'avatar',
    'timezone',
])]
#[Hidden(['password', 'remember_token', 'email_verification_code'])]
class User extends Authenticatable implements FilamentUser, MustVerifyEmailContract
{
    /** @use HasFactory<UserFactory> */
    use HasApiTokens, HasFactory, HasRoles, Notifiable;

    public function canAccessPanel(Panel $panel): bool
    {
        return $this->status === 'active' && ($this->role === 'admin' || $this->hasRole('admin'));
    }

    public function generateEmailVerificationCode(): string
    {
        $code = (string) random_int(100000, 999999);

        $this->forceFill([
            'email_verification_code' => Hash::make($code),
            'email_verification_code_expires_at' => now()->addMinutes(30),
        ])->save();

        return $code;
    }

    public function emailVerificationCodeIsValid(string $code): bool
    {
        if (! $this->email_verification_code || ! $this->email_verification_code_expires_at) {
            return false;
        }

        if ($this->email_verification_code_expires_at->isPast()) {
            return false;
        }

        return Hash::check($code, $this->email_verification_code);
    }

    public function clearEmailVerificationCode(): void
    {
        $this->forceFill([
            'email_verification_code' => null,
            'email_verification_code_expires_at' => null,
        ])->save();
    }

    public function sendEmailVerificationNotification(): void
    {
        $this->notify(new VerifyEmailCode($this->generateEmailVerificationCode()));
    }

    public function hasPaidPlanAccess(): bool
    {
        $this->loadMissing('plan');

        if (! $this->plan) {
            return false;
        }

        return max(
            (float) $this->plan->checkoutPrice('monthly'),
            (float) $this->plan->checkoutPrice('yearly'),
        ) > 0;
    }

    public function plan(): BelongsTo
    {
        return $this->belongsTo(Plan::class);
    }

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

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

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

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

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

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