<?php

namespace App\Models;

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\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;

#[Fillable(['name', 'email', 'password', 'tenant_id', 'is_admin', 'permissions', 'role_preset_id', 'status'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable implements CanResetPasswordContract
{
    use HasFactory, Notifiable, CanResetPassword;

    protected $fillable = ['name', 'email', 'password', 'tenant_id', 'is_admin', 'permissions', 'role_preset_id', 'status'];

    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'password' => 'hashed',
            'is_admin' => 'boolean',
            'permissions' => 'array',
            'status' => 'string',
        ];
    }

    public const STATUS_ACTIVE = 'active';
    public const STATUS_SUSPENDED = 'suspended';
    public const STATUS_PENDING = 'pending';

    public const MODULES = ['individui', 'gruppi', 'eventi', 'documenti', 'mailing', 'viste', 'report', 'settings'];
    public const LEVEL_NONE = 0;
    public const LEVEL_READ = 1;
    public const LEVEL_FULL = 2;

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

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

    public function notifiche(): HasMany
    {
        return $this->hasMany(Notifica::class)->orderBy('created_at', 'desc');
    }

    public function unreadNotifiche(): HasMany
    {
        return $this->hasMany(Notifica::class)->where('is_read', false)->orderBy('created_at', 'desc');
    }

    public function unreadNotificheCount(): int
    {
        return $this->notifiche()->unread()->count();
    }

    public function activityLogs(): HasMany
    {
        return $this->hasMany(ActivityLog::class)->orderBy('created_at', 'desc');
    }

    public function isSuperAdmin(): bool
    {
        return $this->is_admin === true;
    }

    public static function firstUserIsAdmin(): bool
    {
        return self::count() === 1;
    }

    public function isActive(): bool
    {
        return $this->status !== self::STATUS_SUSPENDED;
    }

    public function getPermission(string $module): int
    {
        if ($this->isSuperAdmin()) {
            return self::LEVEL_FULL;
        }

        return $this->permissions[$module] ?? self::LEVEL_NONE;
    }

    public function hasPermission(string $module, int $level = self::LEVEL_READ): bool
    {
        return $this->getPermission($module) >= $level;
    }

    public function canAccess(string $module): bool
    {
        return $this->getPermission($module) >= self::LEVEL_READ;
    }

    public function canManage(string $module): bool
    {
        return $this->getPermission($module) >= self::LEVEL_FULL;
    }

    public function canRead(string $module): bool
    {
        return $this->getPermission($module) >= self::LEVEL_READ;
    }

    public function canWrite(string $module): bool
    {
        return $this->getPermission($module) >= self::LEVEL_FULL;
    }

    public function canDelete(string $module): bool
    {
        return $this->getPermission($module) >= self::LEVEL_FULL;
    }

    public function setPermission(string $module, int $level): self
    {
        $permissions = $this->permissions ?? [];
        $permissions[$module] = $level;
        $this->permissions = $permissions;
        return $this;
    }

    public function setPermissions(array $permissions): self
    {
        $this->permissions = $permissions;
        return $this;
    }

    public function getPermissionsSummary(): array
    {
        $result = [];
        foreach (self::MODULES as $module) {
            $level = $this->getPermission($module);
            $result[$module] = match ($level) {
                self::LEVEL_NONE => 'Nessuno',
                self::LEVEL_READ => 'Lettura',
                self::LEVEL_FULL => 'Completo',
            };
        }
        return $result;
    }

    public function applyRolePreset(RolePreset $preset): self
    {
        $this->role_preset_id = $preset->id;
        $this->permissions = $preset->permissions;
        return $this;
    }

    public function sendPasswordResetNotification($token): void
    {
        $settings = EmailSetting::getActive();
        if (!$settings || empty($settings->smtp_host)) {
            Log::warning('Impossibile inviare reset password: SMTP non configurato');
            return;
        }

        try {
            $smtpUsername = $settings->smtp_username ?: $settings->email_address;
            $smtpPassword = $settings->smtp_password
                ? Crypt::decryptString($settings->smtp_password)
                : $settings->getDecryptedPassword();

            $encryption = $settings->smtp_encryption ?? 'tls';
            $scheme = ($encryption === 'ssl') ? 'smtps' : 'smtp';

            $dsn = sprintf(
                '%s://%s:%s@%s:%d?encryption=%s',
                $scheme,
                rawurlencode($smtpUsername),
                rawurlencode($smtpPassword),
                $settings->smtp_host,
                $settings->smtp_port ?? 587,
                $encryption
            );

            $transport = Transport::fromDsn($dsn);
            $mailer = new Mailer($transport);

            $resetUrl = url('/password/reset/' . $token);

            $fromName = $settings->email_name ?? config('app.name');
            $fromName = preg_replace('/[^\p{L}\p{N}\s]/u', '', $fromName);
            $fromName = trim($fromName) ?: config('app.name');

            $email = (new Email())
                ->from(new Address($settings->email_address, $fromName))
                ->to($this->email)
                ->subject('Reset della password - ' . config('app.name'))
                ->html(view('auth.emails.reset-password', [
                    'user' => $this,
                    'token' => $token,
                    'resetUrl' => $resetUrl,
                    'appName' => config('app.name'),
                ])->render());

            $mailer->send($email);

            Log::info('Password reset email sent', ['email' => $this->email]);
        } catch (\Exception $e) {
            Log::error('Failed to send password reset email', [
                'email' => $this->email,
                'error' => $e->getMessage(),
            ]);
        }
    }
}