<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class Admin extends Authenticatable
{
    use HasFactory, Notifiable;

    /**
     * The guard for admin authentication.
     *
     * @var string
     */
    protected $guard = 'admin';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'role',
        'is_active',
        'created_by',
        'last_login_at',
    ];

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

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'password' => 'hashed',
        'is_active' => 'boolean',
        'last_login_at' => 'datetime',
    ];

    /**
     * Role constants.
     */
    const ROLE_SUPERADMIN = 'superadmin';
    const ROLE_ADMIN = 'admin';

    /**
     * Get the limits for this admin.
     */
    public function limits()
    {
        return $this->hasOne(AdminLimit::class);
    }

    /**
     * Get the individual permission overrides for this admin.
     */
    public function permissionOverrides()
    {
        return $this->hasMany(AdminPermission::class);
    }

    /**
     * Get audit logs for this admin.
     */
    public function auditLogs()
    {
        return $this->hasMany(AdminAuditLog::class);
    }

    /**
     * Get the admin who created this admin.
     */
    public function createdBy()
    {
        return $this->belongsTo(Admin::class, 'created_by');
    }

    /**
     * Get admins created by this admin.
     */
    public function createdAdmins()
    {
        return $this->hasMany(Admin::class, 'created_by');
    }

    /**
     * Get users managed by this admin.
     */
    public function managedUsers()
    {
        return $this->hasMany(User::class, 'managed_by_admin');
    }

    /**
     * Check if admin is SuperAdmin.
     */
    public function isSuperAdmin(): bool
    {
        return $this->role === self::ROLE_SUPERADMIN;
    }

    /**
     * Check if admin is regular Admin.
     */
    public function isAdmin(): bool
    {
        return $this->role === self::ROLE_ADMIN;
    }

    /**
     * Check if admin has a specific permission.
     */
    public function hasPermission(string $permissionKey): bool
    {
        // SuperAdmin has all permissions
        if ($this->isSuperAdmin()) {
            return true;
        }

        // Check for individual override first
        $override = $this->permissionOverrides()
            ->where('permission_key', $permissionKey)
            ->first();
        
        if ($override) {
            return $override->is_allowed;
        }

        // Check role-based permissions
        $rolePermission = RolePermission::where('role', $this->role)
            ->where('permission_key', $permissionKey)
            ->first();

        return $rolePermission ? $rolePermission->is_allowed : false;
    }

    /**
     * Check if admin has any of the given permissions.
     */
    public function hasAnyPermission(array $permissions): bool
    {
        foreach ($permissions as $permission) {
            if ($this->hasPermission($permission)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Check if admin has all of the given permissions.
     */
    public function hasAllPermissions(array $permissions): bool
    {
        foreach ($permissions as $permission) {
            if (!$this->hasPermission($permission)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Get all available permissions for this admin.
     */
    public function getAllPermissions(): array
    {
        if ($this->isSuperAdmin()) {
            return Permission::getSuperAdminPermissions();
        }

        $permissions = [];

        // Get role permissions
        $rolePermissions = RolePermission::where('role', $this->role)
            ->where('is_allowed', true)
            ->pluck('permission_key')
            ->toArray();
        
        $permissions = array_merge($permissions, $rolePermissions);

        // Get individual overrides (add allowed, remove disallowed)
        $overrides = $this->permissionOverrides;
        foreach ($overrides as $override) {
            if ($override->is_allowed && !in_array($override->permission_key, $permissions)) {
                $permissions[] = $override->permission_key;
            } elseif (!$override->is_allowed) {
                $permissions = array_filter($permissions, fn($p) => $p !== $override->permission_key);
            }
        }

        return array_values($permissions);
    }

    /**
     * Get or create limits for this admin.
     */
    public function getOrCreateLimits(): AdminLimit
    {
        if ($this->limits) {
            return $this->limits;
        }

        return $this->limits()->create(AdminLimit::getDefaultLimits());
    }

    /**
     * Check if admin can view full phone numbers.
     */
    public function canViewFullPhone(): bool
    {
        if ($this->isSuperAdmin()) {
            return true;
        }

        return $this->hasPermission('logs.call.view_full') || 
               $this->hasPermission('logs.sms.view_full') ||
               ($this->limits && $this->limits->can_view_full_phone);
    }

    /**
     * Check if admin can view raw logs.
     */
    public function canViewRawLogs(): bool
    {
        if ($this->isSuperAdmin()) {
            return true;
        }

        return $this->limits && $this->limits->can_view_raw_logs;
    }

    /**
     * Check if admin can export data.
     */
    public function canExport(): bool
    {
        if ($this->isSuperAdmin()) {
            return true;
        }

        return $this->hasPermission('logs.export') || 
               $this->hasPermission('analytics.export') ||
               ($this->limits && $this->limits->can_export_reports);
    }

    /**
     * Get the count of users this admin has created/manages.
     */
    public function getManagedUserCount(): int
    {
        return User::where('managed_by_admin', $this->id)->count();
    }

    /**
     * Check if admin can create more users.
     */
    public function canCreateMoreUsers(): bool
    {
        if ($this->isSuperAdmin()) {
            return true;
        }

        $limits = $this->getOrCreateLimits();
        
        if (!$limits->can_create_users) {
            return false;
        }

        return $this->getManagedUserCount() < $limits->max_users;
    }

    /**
     * Get remaining user slots for this admin.
     */
    public function getRemainingUserSlots(): int
    {
        if ($this->isSuperAdmin()) {
            return PHP_INT_MAX;
        }

        $limits = $this->getOrCreateLimits();
        return max(0, $limits->max_users - $this->getManagedUserCount());
    }

    /**
     * Scope: Active admins only.
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope: SuperAdmins only.
     */
    public function scopeSuperAdmins($query)
    {
        return $query->where('role', self::ROLE_SUPERADMIN);
    }

    /**
     * Scope: Regular admins only.
     */
    public function scopeRegularAdmins($query)
    {
        return $query->where('role', self::ROLE_ADMIN);
    }

    /**
     * Update last login timestamp.
     */
    public function recordLogin(): void
    {
        $this->update(['last_login_at' => now()]);
        AdminAuditLog::logAction($this, AdminAuditLog::ACTION_LOGIN);
    }

    /**
     * Log an action performed by this admin.
     */
    public function logAction(
        string $action,
        ?string $resourceType = null,
        ?int $resourceId = null,
        ?array $oldValues = null,
        ?array $newValues = null
    ): AdminAuditLog {
        return AdminAuditLog::logAction(
            $this,
            $action,
            $resourceType,
            $resourceId,
            $oldValues,
            $newValues
        );
    }
}
