<?php

namespace App\Http\Controllers\Api;

use App\Classes\Common;
use App\Classes\PermsSeed;
use App\Http\Controllers\ApiBaseController;
use App\Models\Permission;
use App\Models\Role;
use Examyou\RestAPI\ApiResponse;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use ReflectionClass;

class ModulePermissionController extends ApiBaseController
{
    /**
     * Get all roles with their module-specific permissions
     *
     * @param string $moduleName
     * @return \Examyou\RestAPI\ApiResponse
     */
    public function getRolesWithModulePermissions($moduleName)
    {
        try {
            $roles = \App\Models\Role::with(['perms' => function ($query) use ($moduleName) {
                $query->where('module_name', $moduleName);
            }])->get();

            return ApiResponse::make('Success', [
                'data' => $roles,
                'module' => $moduleName,
            ]);
        } catch (\Exception $e) {
            return ApiResponse::make('Error', [
                'message' => "Failed to fetch roles: {$e->getMessage()}",
            ], [], 500);
        }
    }

    /**
     * Get module permissions grouped by file name
     *
     * @param string $moduleName
     * @return \Examyou\RestAPI\ApiResponse
     */
    public function getModulePermissions($moduleName)
    {
        $groupedPermissions = [];

        $path = base_path("Modules/{$moduleName}/app/Classes/PermsSeed");

        // Check if directory exists
        if (File::isDirectory($path)) {
            // Get all PHP files under this directory
            $files = File::allFiles($path);

            foreach ($files as $file) {
                $filePath = $file->getPathname();
                $fileName = $file->getFilenameWithoutExtension();

                // Get namespace and class name
                $className = $this->getFullClassName($filePath);

                if ($className && class_exists($className)) {
                    $reflection = new ReflectionClass($className);

                    if ($reflection->hasProperty('permissions')) {
                        $property = $reflection->getProperty('permissions');

                        if ($property->isStatic()) {
                            $permissions = $property->getValue();

                            // Process each permission
                            $processedPermissions = [];
                            foreach ($permissions as $key => $permission) {
                                // Add lang_trans if not exists
                                if (!isset($permission['lang_trans'])) {
                                    $permission['lang_trans'] = $this->getPermissionLangTrans($key);
                                }

                                $processedPermissions[$key] = $permission;
                            }

                            // Group by file name (convert to snake_case plural)
                            $groupKey = $this->getPermissionGroupKey($fileName);
                            $groupedPermissions[$groupKey] = $processedPermissions;
                        }
                    }
                }
            }
        }

        return ApiResponse::make('Success', [
            'module' => $moduleName,
            'permissions' => $groupedPermissions,
        ]);
    }

    /**
     * Seed permissions for a module
     *
     * @param string $moduleName
     * @return \Examyou\RestAPI\ApiResponse
     */
    public function seedModulePermissions($moduleName)
    {
        try {
            // Call the PermsSeed class to seed permissions
            PermsSeed::seedModulePermissions($moduleName);

            return ApiResponse::make('Success', [
                'message' => "Permissions for module '{$moduleName}' have been seeded successfully.",
                'module' => $moduleName,
            ]);
        } catch (\Exception $e) {
            return ApiResponse::make('Error', [
                'message' => "Failed to seed permissions: {$e->getMessage()}",
                'module' => $moduleName,
            ], [], 500);
        }
    }

    /**
     * Update role permissions
     * Request body: { role_id: xid, permission: name }
     *
     * @param \Illuminate\Http\Request $request
     * @return \Examyou\RestAPI\ApiResponse
     */
    public function updateRolePermissions(\Illuminate\Http\Request $request)
    {
        $request->validate([
            'role_id' => 'required|string',
            'permission' => 'required|string',
        ]);

        // Find role by xid (hash ID) - xid is an accessor, not a DB column
        // So we need to decode it to get the actual ID
        $roleId = Common::getIdFromHash($request->role_id);
        $role = Role::findOrFail($roleId);

        // Find permission by name
        $permission = Permission::where('name', $request->permission)->firstOrFail();

        // Check if the permission is already attached
        $hasPermission = $role->perms()->where('permission_id', $permission->id)->exists();

        if ($hasPermission) {
            // Detach the permission
            $role->perms()->detach($permission->id);
            $action = 'removed';
        } else {
            // Attach the permission
            $role->perms()->attach($permission->id);
            $action = 'added';
        }

        return ApiResponse::make('Success', [
            'action' => $action,
            'role_id' => $role->xid,
            'permission_name' => $permission->name,
            'permission_id' => $permission->xid,
        ]);
    }

    /**
     * Bulk update role permissions (add or remove multiple permissions at once)
     * Request body: { role_id: xid, permissions: [names], action: 'add'|'remove' }
     *
     * @param \Illuminate\Http\Request $request
     * @return \Examyou\RestAPI\ApiResponse
     */
    public function bulkUpdateRolePermissions(\Illuminate\Http\Request $request)
    {
        $request->validate([
            'role_id' => 'required|string',
            'permissions' => 'required|array',
            'permissions.*' => 'string',
            'action' => 'required|in:add,remove',
        ]);

        // Find role by xid
        $roleId = Common::getIdFromHash($request->role_id);
        $role = Role::findOrFail($roleId);

        // Get all permission IDs from names
        $permissions = Permission::whereIn('name', $request->permissions)->get();
        $permissionIds = $permissions->pluck('id')->toArray();

        if (empty($permissionIds)) {
            return ApiResponse::make('Error', [
                'message' => 'No valid permissions found',
            ], [], 400);
        }

        if ($request->action === 'add') {
            // Sync will add only new permissions without removing existing ones
            // Use syncWithoutDetaching to add permissions
            $role->perms()->syncWithoutDetaching($permissionIds);
            $message = "All permissions added to role \"{$role->display_name}\"";
        } else {
            // Remove the specified permissions
            $role->perms()->detach($permissionIds);
            $message = "All permissions removed from role \"{$role->display_name}\"";
        }

        return ApiResponse::make('Success', [
            'message' => $message,
            'role_id' => $role->xid,
            'action' => $request->action,
            'count' => count($permissionIds),
        ]);
    }

    /**
     * Bulk update permissions for multiple roles at once
     * Request body: { role_ids: [xids], permissions: [names], action: 'add'|'remove' }
     *
     * @param \Illuminate\Http\Request $request
     * @return \Examyou\RestAPI\ApiResponse
     */
    public function bulkUpdateAllRolesPermissions(\Illuminate\Http\Request $request)
    {
        $request->validate([
            'role_ids' => 'required|array',
            'role_ids.*' => 'string',
            'permissions' => 'required|array',
            'permissions.*' => 'string',
            'action' => 'required|in:add,remove',
        ]);

        // Decode all role xids to numeric IDs
        $roleIds = [];
        foreach ($request->role_ids as $xid) {
            $id = Common::getIdFromHash($xid);
            if ($id) {
                $roleIds[] = $id;
            }
        }

        if (empty($roleIds)) {
            return ApiResponse::make('Error', [
                'message' => 'No valid roles found',
            ], [], 400);
        }

        // Get all roles (excluding admin role for safety)
        $roles = Role::whereIn('id', $roleIds)
            ->where('name', '!=', 'admin')
            ->get();

        if ($roles->isEmpty()) {
            return ApiResponse::make('Error', [
                'message' => 'No valid non-admin roles found',
            ], [], 400);
        }

        // Get all permission IDs from names
        $permissions = Permission::whereIn('name', $request->permissions)->get();
        $permissionIds = $permissions->pluck('id')->toArray();

        if (empty($permissionIds)) {
            return ApiResponse::make('Error', [
                'message' => 'No valid permissions found',
            ], [], 400);
        }

        // Update permissions for each role
        $updatedCount = 0;
        foreach ($roles as $role) {
            if ($request->action === 'add') {
                $role->perms()->syncWithoutDetaching($permissionIds);
            } else {
                $role->perms()->detach($permissionIds);
            }
            $updatedCount++;
        }

        $actionText = $request->action === 'add' ? 'added to' : 'removed from';
        $message = count($permissionIds) . " permission(s) {$actionText} {$updatedCount} role(s)";

        return ApiResponse::make('Success', [
            'message' => $message,
            'action' => $request->action,
            'roles_updated' => $updatedCount,
            'permissions_count' => count($permissionIds),
        ]);
    }

    /**
     * Convert file name to permission group key
     * Example: "PostPermsSeed" -> "posts"
     *
     * @param string $fileName
     * @return string
     */
    protected function getPermissionGroupKey(string $fileName): string
    {
        // Remove "PermsSeed" suffix
        $name = Str::replaceLast('PermsSeed', '', $fileName);

        // Convert CamelCase to snake_case
        $snakeCase = Str::snake($name);

        // Pluralize
        return Str::plural($snakeCase);
    }

    /**
     * Get language translation key for permission
     *
     * @param string $permissionKey
     * @return string
     */
    protected function getPermissionLangTrans(string $permissionKey): string
    {
        // Check if permission ends with common suffixes
        $suffixes = [
            '_view' => 'view',
            '_create' => 'create',
            '_edit' => 'edit',
            '_delete' => 'delete',
            '_dashboard' => 'dashboard',
        ];

        foreach ($suffixes as $suffix => $type) {
            if (str_ends_with($permissionKey, $suffix)) {
                return "common.{$type}";
            }
        }

        // Return the permission key itself as fallback
        return $permissionKey;
    }

    /**
     * Extract full class name (namespace + class) from file.
     *
     * @param string $filePath
     * @return string|null
     */
    protected function getFullClassName(string $filePath): ?string
    {
        $contents = file_get_contents($filePath);

        if (
            preg_match('/namespace\s+([^;]+);/', $contents, $namespaceMatch) &&
            preg_match('/class\s+([^\s]+)/', $contents, $classMatch)
        ) {
            return $namespaceMatch[1] . '\\' . $classMatch[1];
        }

        return null;
    }
}
