<?php

namespace App\Services\Auth;

use App\Models\User;
use App\Models\Role;
use App\Models\Permission;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class RoleBasedAccessService
{
    /**
     * Cache TTL for permissions (in minutes).
     */
    protected const CACHE_TTL = 60;

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

        // Get user permissions from cache or database
        $permissions = $this->getUserPermissions($user);

        return in_array($permission, $permissions);
    }

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

        return false;
    }

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

        return true;
    }

    /**
     * Check if user has specific role.
     */
    public function hasRole(User $user, string $role): bool
    {
        return $user->role?->name === $role;
    }

    /**
     * Check if user has any of the given roles.
     */
    public function hasAnyRole(User $user, array $roles): bool
    {
        return in_array($user->role?->name, $roles);
    }

    /**
     * Check if user is super admin.
     */
    public function isSuperAdmin(User $user): bool
    {
        return $this->hasRole($user, 'super_admin');
    }

    /**
     * Check if user is admin (super admin or admin).
     */
    public function isAdmin(User $user): bool
    {
        return $this->hasAnyRole($user, ['super_admin', 'admin']);
    }

    /**
     * Check if user has warehouse access.
     */
    public function hasWarehouseAccess(User $user): bool
    {
        $warehousePermissions = [
            'warehouse.dashboard.view',
            'warehouse.suppliers.view',
            'warehouse.projects.view',
            'warehouse.items.view',
            'warehouse.inventory.view',
            'warehouse.incoming.view',
            'warehouse.outgoing.view',
            'warehouse.returns.view',
        ];

        return $this->hasAnyPermission($user, $warehousePermissions);
    }

    /**
     * Get all user permissions.
     */
    public function getUserPermissions(User $user): array
    {
        $cacheKey = "user_permissions_{$user->id}";

        return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($user) {
            if (!$user->role) {
                return [];
            }

            return $user->role->permissions()->pluck('name')->toArray();
        });
    }

    /**
     * Get user warehouse permissions.
     */
    public function getUserWarehousePermissions(User $user): array
    {
        $allPermissions = $this->getUserPermissions($user);

        return array_filter($allPermissions, function ($permission) {
            return strpos($permission, 'warehouse.') === 0;
        });
    }

    /**
     * Get user role display name.
     */
    public function getUserRoleDisplayName(User $user): ?string
    {
        return $user->role?->display_name;
    }

    /**
     * Check if user can manage other users.
     */
    public function canManageUsers(User $user): bool
    {
        return $this->hasPermission($user, 'users.view');
    }

    /**
     * Check if user can manage roles.
     */
    public function canManageRoles(User $user): bool
    {
        return $this->hasPermission($user, 'roles.view');
    }

    /**
     * Check if user can manage warehouse settings.
     */
    public function canManageWarehouseSettings(User $user): bool
    {
        return $this->hasPermission($user, 'warehouse.settings.manage');
    }

    /**
     * Check if user can approve warehouse transactions.
     */
    public function canApproveWarehouseTransactions(User $user): bool
    {
        return $this->hasAnyPermission($user, [
            'warehouse.outgoing.approve',
            'warehouse.returns.process'
        ]);
    }

    /**
     * Check if user can view warehouse reports.
     */
    public function canViewWarehouseReports(User $user): bool
    {
        return $this->hasPermission($user, 'warehouse.reports.view');
    }

    /**
     * Check warehouse operation permissions.
     */
    public function canPerformWarehouseOperation(User $user, string $operation, string $module): bool
    {
        $permission = "warehouse.{$module}.{$operation}";
        return $this->hasPermission($user, $permission);
    }

    /**
     * Get user's warehouse role level.
     */
    public function getWarehouseRoleLevel(User $user): string
    {
        if ($this->hasRole($user, 'warehouse_manager')) {
            return 'manager';
        }

        if ($this->hasRole($user, 'warehouse_supervisor')) {
            return 'supervisor';
        }

        if ($this->hasRole($user, 'warehouse_clerk')) {
            return 'clerk';
        }

        if ($this->hasRole($user, 'project_manager')) {
            return 'project_manager';
        }

        if ($this->hasRole($user, 'warehouse_viewer')) {
            return 'viewer';
        }

        return 'none';
    }

    /**
     * Clear user permissions cache.
     */
    public function clearUserPermissionsCache(User $user): void
    {
        $cacheKey = "user_permissions_{$user->id}";
        Cache::forget($cacheKey);
    }

    /**
     * Clear all permissions cache.
     */
    public function clearAllPermissionsCache(): void
    {
        $users = User::all();
        foreach ($users as $user) {
            $this->clearUserPermissionsCache($user);
        }
    }

    /**
     * Assign role to user.
     */
    public function assignRole(User $user, Role $role): bool
    {
        try {
            $user->role()->associate($role);
            $user->save();

            // Clear permissions cache
            $this->clearUserPermissionsCache($user);

            // Log the role assignment
            Log::info('Role assigned to user', [
                'user_id' => $user->id,
                'user_email' => $user->email,
                'role_id' => $role->id,
                'role_name' => $role->name,
                'assigned_by' => auth()->id()
            ]);

            return true;
        } catch (\Exception $e) {
            Log::error('Failed to assign role to user', [
                'user_id' => $user->id,
                'role_id' => $role->id,
                'error' => $e->getMessage()
            ]);

            return false;
        }
    }

    /**
     * Remove role from user.
     */
    public function removeRole(User $user): bool
    {
        try {
            $oldRole = $user->role;
            $user->role()->dissociate();
            $user->save();

            // Clear permissions cache
            $this->clearUserPermissionsCache($user);

            // Log the role removal
            Log::info('Role removed from user', [
                'user_id' => $user->id,
                'user_email' => $user->email,
                'old_role_id' => $oldRole?->id,
                'old_role_name' => $oldRole?->name,
                'removed_by' => auth()->id()
            ]);

            return true;
        } catch (\Exception $e) {
            Log::error('Failed to remove role from user', [
                'user_id' => $user->id,
                'error' => $e->getMessage()
            ]);

            return false;
        }
    }

    /**
     * Get available warehouse roles.
     */
    public function getWarehouseRoles(): array
    {
        return Role::whereIn('name', [
            'warehouse_manager',
            'warehouse_supervisor',
            'warehouse_clerk',
            'project_manager',
            'warehouse_viewer'
        ])->get()->toArray();
    }

    /**
     * Get permission hierarchy for warehouse operations.
     */
    public function getWarehousePermissionHierarchy(): array
    {
        return [
            'warehouse_manager' => [
                'warehouse.dashboard.view',
                'warehouse.suppliers.view',
                'warehouse.suppliers.create',
                'warehouse.suppliers.edit',
                'warehouse.suppliers.delete',
                'warehouse.projects.view',
                'warehouse.projects.create',
                'warehouse.projects.edit',
                'warehouse.projects.delete',
                'warehouse.items.view',
                'warehouse.items.create',
                'warehouse.items.edit',
                'warehouse.items.delete',
                'warehouse.inventory.view',
                'warehouse.inventory.adjust',
                'warehouse.inventory.transfer',
                'warehouse.inventory.count',
                'warehouse.incoming.view',
                'warehouse.incoming.create',
                'warehouse.incoming.edit',
                'warehouse.incoming.delete',
                'warehouse.incoming.process',
                'warehouse.outgoing.view',
                'warehouse.outgoing.create',
                'warehouse.outgoing.edit',
                'warehouse.outgoing.delete',
                'warehouse.outgoing.approve',
                'warehouse.outgoing.process',
                'warehouse.returns.view',
                'warehouse.returns.create',
                'warehouse.returns.edit',
                'warehouse.returns.delete',
                'warehouse.returns.process',
                'warehouse.reports.view',
                'warehouse.settings.manage',
            ],
            'warehouse_supervisor' => [
                'warehouse.dashboard.view',
                'warehouse.suppliers.view',
                'warehouse.projects.view',
                'warehouse.items.view',
                'warehouse.items.create',
                'warehouse.items.edit',
                'warehouse.inventory.view',
                'warehouse.inventory.adjust',
                'warehouse.inventory.transfer',
                'warehouse.incoming.view',
                'warehouse.incoming.create',
                'warehouse.incoming.edit',
                'warehouse.incoming.process',
                'warehouse.outgoing.view',
                'warehouse.outgoing.create',
                'warehouse.outgoing.edit',
                'warehouse.outgoing.process',
                'warehouse.returns.view',
                'warehouse.returns.create',
                'warehouse.returns.edit',
                'warehouse.returns.process',
                'warehouse.reports.view',
            ],
            'warehouse_clerk' => [
                'warehouse.dashboard.view',
                'warehouse.suppliers.view',
                'warehouse.projects.view',
                'warehouse.items.view',
                'warehouse.inventory.view',
                'warehouse.incoming.view',
                'warehouse.incoming.create',
                'warehouse.incoming.edit',
                'warehouse.outgoing.view',
                'warehouse.outgoing.create',
                'warehouse.outgoing.edit',
                'warehouse.returns.view',
                'warehouse.returns.create',
                'warehouse.returns.edit',
            ],
            'project_manager' => [
                'warehouse.dashboard.view',
                'warehouse.projects.view',
                'warehouse.projects.create',
                'warehouse.projects.edit',
                'warehouse.items.view',
                'warehouse.inventory.view',
                'warehouse.outgoing.view',
                'warehouse.outgoing.create',
                'warehouse.outgoing.edit',
                'warehouse.reports.view',
            ],
            'warehouse_viewer' => [
                'warehouse.dashboard.view',
                'warehouse.suppliers.view',
                'warehouse.projects.view',
                'warehouse.items.view',
                'warehouse.inventory.view',
                'warehouse.incoming.view',
                'warehouse.outgoing.view',
                'warehouse.returns.view',
                'warehouse.reports.view',
            ],
        ];
    }
}