<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;

class RoleController extends Controller
{
    /**
     * Permission modules and abilities displayed in the matrix.
     */
    private array $permissionMatrix = [
        'dashboard' => 'Dashboard',
        'customers' => 'Customers',
        'staff' => 'Staff',
        'roles' => 'Roles',
        'products' => 'Products',
        'categories' => 'Categories',
        'brands' => 'Brands',
        'attributes' => 'Attributes',
        'orders' => 'Orders',
        // 'tickets' => 'Tickets',
        'coupons' => 'Coupons',
        // 'reviews' => 'Reviews',
        'banners' => 'Banners',
        'announcements' => 'Announcements',
        'shipping-methods' => 'Shipping Methods',
        'units' => 'Units',
        'taxes' => 'Taxes',
        'carriers' => 'Carriers',
    ];

    private array $abilities = ['view', 'create', 'update', 'delete'];

    public function index()
    {
        $this->ensurePermissionsExist();

        $roles = Role::orderBy('name')->paginate(15);
        
        // Manually count users for each role
        foreach ($roles as $role) {
            $role->users_count = DB::table('model_has_roles')
                ->where('role_id', $role->id)
                ->where('model_type', User::class)
                ->count();
        }

        return view('admin.roles.index', [
            'roles' => $roles,
        ]);
    }

    public function create()
    {
        $this->ensurePermissionsExist();

        return view('admin.roles.create', [
            'permissionMatrix' => $this->permissionMatrix,
            'abilities' => $this->abilities,
            'assignedPermissions' => [], // Empty array for new role
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $this->ensurePermissionsExist();

        $availablePermissions = $this->availablePermissions();

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:100', 'unique:roles,name'],
            'display_name' => ['nullable', 'string', 'max:100'],
            'description' => ['nullable', 'string'], // UI-only field, ignored
            'max_discount_percentage' => ['nullable', 'numeric', 'min:0', 'max:100'],
            'otp_required_for_discount' => ['nullable', 'boolean'],
            'permissions' => ['nullable', 'array'],
            'permissions.*' => ['string', Rule::in($availablePermissions)],
        ]);

        // Use name field (display_name is UI-only, description is ignored)
        $role = Role::create([
            'name' => $validated['name'],
            'guard_name' => 'web',
            'max_discount_percentage' => $validated['max_discount_percentage'] ?? null,
            'otp_required_for_discount' => $validated['otp_required_for_discount'] ?? false,
        ]);

        $role->syncPermissions($validated['permissions'] ?? []);

        return redirect()->route('admin.roles.index')->with('success', 'Role created successfully.');
    }

    public function edit(Role $role)
    {
        $this->ensurePermissionsExist();

        // Get users with this role
        $usersWithRole = DB::table('model_has_roles')
            ->where('role_id', $role->id)
            ->where('model_type', User::class)
            ->pluck('model_id')
            ->toArray();

        // Set users_count attribute (used in view)
        $role->users_count = count($usersWithRole);

        $assignedUsers = User::whereIn('id', $usersWithRole)->get();
        // Only list staff users for assignment
        $allUsers = User::where('user_type', 'staff')->get();

        return view('admin.roles.edit', [
            'role' => $role->load('permissions'),
            'permissionMatrix' => $this->permissionMatrix,
            'abilities' => $this->abilities,
            'assignedPermissions' => $role->permissions->pluck('name')->toArray(),
            'assignedUsers' => $assignedUsers,
            'allUsers' => $allUsers,
            'assignedUserIds' => $usersWithRole,
        ]);
    }

    public function update(Request $request, Role $role): RedirectResponse
    {
        $this->ensurePermissionsExist();

        $availablePermissions = $this->availablePermissions();

        $validated = $request->validate([
            'name' => [
                'required',
                'string',
                'max:100',
                Rule::unique('roles', 'name')->ignore($role->id),
            ],
            'display_name' => ['nullable', 'string', 'max:100'],
            'description' => ['nullable', 'string'],
            'max_discount_percentage' => ['nullable', 'numeric', 'min:0', 'max:100'],
            'otp_required_for_discount' => ['nullable', 'boolean'],
            'permissions' => ['nullable', 'array'],
            'permissions.*' => ['string', Rule::in($availablePermissions)],
            'users' => ['nullable', 'array'],
            'users.*' => ['exists:users,id'],
        ]);

        // Use name field (description is ignored as it's UI-only)
        $role->update([
            'name' => $validated['name'],
            'max_discount_percentage' => $validated['max_discount_percentage'] ?? null,
            'otp_required_for_discount' => $validated['otp_required_for_discount'] ?? false,
        ]);

        $role->syncPermissions($validated['permissions'] ?? []);

        // Sync users assigned to this role
        $selectedUserIds = $validated['users'] ?? [];
        
        // Get all users currently with this role
        $currentUsers = User::role($role->name)->get();
        
        // Remove role from users not in the new list
        foreach ($currentUsers as $user) {
            if (!in_array($user->id, $selectedUserIds)) {
                $user->removeRole($role);
                // Sync user_type after removing role
                $this->syncUserTypeFromRoles($user);
            }
        }
        
        // Assign role to selected users
        if (!empty($selectedUserIds)) {
            $usersToAssign = User::whereIn('id', $selectedUserIds)->get();
            foreach ($usersToAssign as $user) {
                if (!$user->hasRole($role->name)) {
                    $user->assignRole($role);
                }
                // Refresh user to reload roles
                $user->refresh();
                // Sync user_type after assigning role
                $this->syncUserTypeFromRoles($user);
            }
        }

        // Clear permission cache to ensure roles are refreshed
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        return redirect()->route('admin.roles.index')->with('success', 'Role updated successfully.');
    }

    public function destroy(Role $role): RedirectResponse
    {
        // Check if role is assigned to any users via the pivot table
        $usersCount = DB::table('model_has_roles')
            ->where('role_id', $role->id)
            ->where('model_type', User::class)
            ->count();

        if ($usersCount > 0) {
            return redirect()
                ->route('admin.roles.index')
                ->with('error', 'Cannot delete role because it is assigned to ' . $usersCount . ' user(s).');
        }

        $role->delete();

        return redirect()->route('admin.roles.index')->with('success', 'Role deleted successfully.');
    }

    /**
     * Ensure every permission in the matrix exists in the database.
     */
    private function ensurePermissionsExist(): void
    {
        foreach ($this->permissionMatrix as $module => $label) {
            // Dashboard has special permissions (view-kpis, view-dashlets)
            if ($module === 'dashboard') {
                Permission::firstOrCreate(
                    ['name' => 'dashboard.view-kpis', 'guard_name' => 'web'],
                    ['guard_name' => 'web']
                );
                Permission::firstOrCreate(
                    ['name' => 'dashboard.view-dashlets', 'guard_name' => 'web'],
                    ['guard_name' => 'web']
                );
            } else {
                // Other modules use standard abilities
                foreach ($this->abilities as $ability) {
                    Permission::firstOrCreate(
                        ['name' => "{$module}.{$ability}", 'guard_name' => 'web'],
                        ['guard_name' => 'web']
                    );
                }
            }
        }
        
        // Ensure standalone permissions exist
        $standalonePermissions = [
            'whatsapp.credits',
            'whatsapp.templates',
            'whatsapp.logs',
            'manage reviews',
            'manage shipping',
            'pos_access',
            'reports.sales',
            'reports.salesman',
            'reports.profit',
            'reports.top-products',
            'reports.payments',
            'reports.gst',
            'reports.delivery',
            'reports.day-ledger.view',
            'reports.day-ledger.manage',
            'reports.day-ledger.close',
            'reports.day-ledger.reopen',
            'settings.general',
            'settings.payment',
            'settings.sms',
            'settings.ticket',
            'settings.carriers',
            'settings.countries',
            'settings.states',
            'settings.cities',
            'products.restock',
            'stock-audit.view',
            'stock-audit.create',
            'stock-adjustments.manage',
            'stock-adjustments.view',
            'reports.stock-audit',
            'reports.stock-adjustments',
            'tickets.view',
            'tickets.assign',
            'tickets.reply',
            'tickets.update',
        ];
        
        foreach ($standalonePermissions as $permission) {
            Permission::firstOrCreate(
                ['name' => $permission, 'guard_name' => 'web'],
                ['guard_name' => 'web']
            );
        }
    }

    /**
     * Flattened list of allowed permission names.
     */
    private function availablePermissions(): array
    {
        $permissions = [];

        foreach ($this->permissionMatrix as $module => $label) {
            // Dashboard has special permissions
            if ($module === 'dashboard') {
                $permissions[] = "dashboard.view-kpis";
                $permissions[] = "dashboard.view-dashlets";
            } else {
                // Other modules use standard abilities
                foreach ($this->abilities as $ability) {
                    $permissions[] = "{$module}.{$ability}";
                }
            }
        }
        $permissions[] = "whatsapp.credits";
        $permissions[] = "whatsapp.templates";
        $permissions[] = "whatsapp.logs";
        $permissions[] = "manage reviews";
        $permissions[] = "manage shipping";
        $permissions[] = "pos_access";
        $permissions[] = "reports.sales";
        $permissions[] = "reports.salesman";
        $permissions[] = "reports.profit";
        $permissions[] = "reports.top-products";
        $permissions[] = "reports.payments";
        $permissions[] = "reports.gst";
        $permissions[] = "reports.delivery";
        $permissions[] = "reports.day-ledger.view";
        $permissions[] = "reports.day-ledger.manage";
        $permissions[] = "reports.day-ledger.close";
        $permissions[] = "reports.day-ledger.reopen";
        $permissions[] = "settings.general";
        $permissions[] = "settings.payment";
        $permissions[] = "settings.sms";
        $permissions[] = "settings.ticket";
        $permissions[] = "settings.carriers";
        $permissions[] = "settings.countries";
        $permissions[] = "settings.states";
        $permissions[] = "settings.cities";
        $permissions[] = "products.restock";
        $permissions[] = "stock-audit.view";
        $permissions[] = "stock-audit.create";
        $permissions[] = "stock-adjustments.manage";
        $permissions[] = "stock-adjustments.view";
        $permissions[] = "reports.stock-audit";
        $permissions[] = "reports.stock-adjustments";
        $permissions[] = "tickets.view";
        $permissions[] = "tickets.assign";
        $permissions[] = "tickets.reply";
        $permissions[] = "tickets.update";

        return $permissions;
    }

    /**
     * Sync user_type based on user's roles
     */
    private function syncUserTypeFromRoles(User $user): void
    {
        $userType = 'customer'; // default
        
        // Check if user has admin role
        if ($user->isAdmin()) {
            $userType = 'admin';
        } 
        // Check if user has staff role (but not admin)
        elseif ($user->isStaff()) {
            $userType = 'staff';
        }
        
        // Update user_type if it has changed
        if ($user->user_type !== $userType) {
            $user->update(['user_type' => $userType]);
        }
    }
}
