<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use App\Enums\UserRole;
use App\Enums\UserStatus;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
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\Str;

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

    protected $keyType = 'string';
    public $incrementing = false;

    protected $fillable = [
        'name',
        'email',
        'password',
        'status',
        'role',
        'email_verified_at',
        'reminders_enabled',
        'notify_in_app',
        'notify_email',
        'notify_push',
        'settings',
        'notification_settings',
        'locale',
        'timezone',
        'meta',
        'deletion_requested_at',
    ];

    protected $hidden = [
        'password',
        'remember_token',
    ];

    protected $casts = [
        'status' => UserStatus::class,
        'role'   => UserRole::class,
        'meta'                  => 'array',
        'settings'              => 'array',
        'notification_settings' => 'array',
        'email_verified_at'     => 'datetime',
    ];


    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            if (!$model->id) {
                $model->id = (string) Str::uuid();
            }
        });
    }

    // RELATIONS
    public function tokens()
    {
        return $this->hasMany(ApiToken::class);
    }

    public function devices()
    {
        return $this->hasMany(Device::class);
    }

    public function reminders()
    {
        return $this->hasMany(Reminder::class);
    }

    public function activities()
    {
        return $this->hasMany(Activity::class);
    }

    public function contacts()
    {
        return $this->hasMany(Contact::class);
    }

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

    public function subscription()
    {
        // Aktive oder geschenkte Subscription bevorzugen; bei mehreren die neueste nach created_at
        return $this->hasOne(Subscription::class)
            ->ofMany([
                'created_at' => 'max',
            ], function ($query) {
                $query->whereIn('status', [
                    \App\Enums\SubscriptionStatus::Active->value,
                    \App\Enums\SubscriptionStatus::Gifted->value,
                ]);
            });
    }

    public function latestSubscription()
    {
        return $this->hasOne(Subscription::class)->latestOfMany('created_at');
    }

    public function agentLogs()
    {
        return $this->hasMany(\App\Models\AgentLog::class);
    }

    public function events()
    {
        return $this->hasMany(\App\Models\Event::class);
    }

    public function automations()
    {
        return $this->hasMany(Automation::class);
    }

    public function calendarIntegrations()
    {
        return $this->hasMany(CalendarIntegration::class);
    }

    public function calendarIntegration(string $provider): ?CalendarIntegration
    {
        return $this->calendarIntegrations()->where('provider', $provider)->first();
    }

    // ── Credits ───────────────────────────────────────────────────────

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

    /**
     * Verfügbares Guthaben (alle Einzahlungen minus usage-Abbuchungen)
     * Der monatliche Reset bucht Über-Plan-Verbrauch als negative usage-Transaktionen.
     */
    public function getBonusCreditsAttribute(): int
    {
        return max(0, (int) $this->creditTransactions()->sum('amount'));
    }

    public function getCreditBalanceAttribute(): int
    {
        return $this->bonus_credits;
    }

    public function getMonthlyUsageAttribute(): int
    {
        return (int) $this->agentLogs()
            ->where('created_at', '>=', now()->startOfMonth())
            ->sum('credits');
    }

    /**
     * Effektives Limit = Plan-Limit + verfügbares Guthaben.
     * 0 = unlimited (Developer/Admin/Super Admin).
     */
    public function getEffectiveLimitAttribute(): int
    {
        $planLimit = $this->subscription?->plan?->credit_limit ?? 0;
        if ($planLimit === 0) return 0;

        return $planLimit + $this->bonus_credits;
    }

    public function getEffectiveUsageAttribute(): int
    {
        return $this->monthly_usage;
    }

    public function getUsagePercentAttribute(): int
    {
        $limit = $this->effective_limit;
        if ($limit === 0) return 0;

        return min(100, (int) round(($this->effective_usage / $limit) * 100));
    }

    // Rollen-Prüfungen

    public function hasRole(string|UserRole $role): bool
    {
        $role = $role instanceof UserRole ? $role : UserRole::from($role);
        return $this->role === $role;
    }

    public function hasAnyRole(array $roles): bool
    {
        foreach ($roles as $role) {
            $r = $role instanceof UserRole ? $role : UserRole::from($role);
            if ($this->role === $r) return true;
        }
        return false;
    }

    public function hasAtLeastRole(string|UserRole $role): bool
    {
        $role = $role instanceof UserRole ? $role : UserRole::from($role);
        return $this->role->hierarchy() >= $role->hierarchy();
    }

    public function isAdmin(): bool
    {
        return $this->hasAnyRole([UserRole::Admin, UserRole::SuperAdmin]);
    }

    public function isSuperAdmin(): bool
    {
        return $this->role === UserRole::SuperAdmin;
    }

    public function isSupport(): bool
    {
        return $this->hasAtLeastRole(UserRole::Support);
    }

    public function isDeveloper(): bool
    {
        return $this->hasAtLeastRole(UserRole::Developer);
    }

    public function isUnlimitedUser(): bool
    {
        return $this->hasAnyRole([UserRole::Admin, UserRole::SuperAdmin, UserRole::Developer]);
    }

    public function isInternalUser(): bool
    {
        return $this->hasAnyRole([
            UserRole::Admin, UserRole::SuperAdmin,
            UserRole::Developer, UserRole::Support,
        ]);
    }

    public function isBetaTester(): bool
    {
        return $this->hasAnyRole([
            UserRole::BetaTester, UserRole::Support,
            UserRole::Developer, UserRole::Admin, UserRole::SuperAdmin,
        ]);
    }

    public function hasFeature(string $key): bool
    {
        // Interne User haben alle Features
        if ($this->isInternalUser()) return true;

        $sub = $this->subscription;
        if (!$sub || !$sub->isActive()) return false;
        return $sub->plan?->features()->where('key', $key)->exists() ?? false;
    }

    public function eventsShared()
    {
        return $this->belongsToMany(Event::class, 'event_user');
    }

    public function notes()
    {
        return $this->hasMany(Note::class);
    }

    public function tasks()
    {
        return $this->hasMany(Task::class);
    }

    public function verifications()
    {
        return $this->hasMany(Verification::class);
    }

    public function emailLogs()
    {
        return $this->hasMany(EmailLog::class);
    }

    public function getSmtpSettingsAttribute(): array
    {
        $s = $this->settings ?? [];
        return [
            'host'         => $s['smtp_host']       ?? null,
            'port'         => $s['smtp_port']        ?? 587,
            'encryption'   => $s['smtp_encryption']  ?? 'tls',
            'username'     => $s['smtp_user']        ?? null,
            'password'     => $s['smtp_password']    ?? null,
            'from_address' => $s['smtp_from_address'] ?? null,
            'from_name'    => $s['smtp_from_name']   ?? null,
        ];
    }

    public function affiliate()
    {
        return $this->hasOne(Affiliate::class);
    }

    public function referredBy()
    {
        return $this->hasOne(AffiliateReferral::class, 'referred_user_id');
    }

    public function requestDeletion()
    {
        $this->update([
            'deletion_requested_at' => now(),
        ]);

        $this->delete();
    }

    public function anonymize()
    {
        $this->update([
            'name' => 'Deleted User',
            'email' => 'deleted_'.$this->id.'@example.com',
            'password' => null,
            'timezone' => null,
            'locale' => null,
            'settings' => null,
        ]);
    }
}
