#!/usr/bin/env bash
set -Eeuo pipefail

PROJECT="/home/itouchdigitalin/public_html/app"
STAMP="$(date +%Y%m%d_%H%M%S)"
BACKUP="/root/itouch-whitelabel-admin-backup-$STAMP"

cd "$PROJECT"

if [ "$(id -u)" -ne 0 ]; then
    echo "STOP: run this installer as root."
    exit 1
fi

echo "============================================================"
echo " i-Touch White-label Admin Panel Installer"
echo " Tenant admin + clients + resellers + strict wallet funding"
echo "============================================================"
echo "Project : $PROJECT"
echo "Backup  : $BACKUP"
echo

REQUIRED=(
    artisan
    routes/web.php
    app/Models/Reseller.php
    app/Models/ResellerUser.php
    app/Models/Client.php
    app/Models/Wallet.php
    app/Models/BillingFixedCharge.php
    app/Services/Billing/WalletService.php
    app/Services/Billing/BillingMoney.php
    app/Http/Middleware/EnsureResellerAuthenticated.php
    app/Http/Controllers/Reseller/AuthController.php
    package.json
)

for f in "${REQUIRED[@]}"; do
    if [ ! -f "$f" ]; then
        echo "STOP: required file missing: $f"
        exit 1
    fi
done

echo "===== PRE-FLIGHT SCHEMA ====="
SCHEMA_CHECK="$(php artisan tinker --execute='
use Illuminate\Support\Facades\Schema;
echo (
    Schema::hasColumn("resellers","parent_reseller_id")
    && Schema::hasColumn("resellers","white_label_enabled")
    && Schema::hasColumn("clients","reseller_id")
    && Schema::hasTable("wallets")
    && Schema::hasTable("billing_fixed_charges")
) ? "WL_SCHEMA_OK" : "WL_SCHEMA_BAD";
' 2>/dev/null || true)"

if ! printf '%s' "$SCHEMA_CHECK" | grep -q "WL_SCHEMA_OK"; then
    echo "STOP: current white-label/reseller schema is not ready."
    echo "Expected: parent_reseller_id, white_label_enabled, client reseller_id, wallets and billing_fixed_charges."
    exit 1
fi

OWNER_CHECK="$(php artisan tinker --execute='
echo \App\Models\Reseller::query()
    ->whereNull("parent_reseller_id")
    ->where("white_label_enabled", true)
    ->exists() ? "WL_OWNER_OK" : "WL_OWNER_MISSING";
' 2>/dev/null || true)"

if ! printf '%s' "$OWNER_CHECK" | grep -q "WL_OWNER_OK"; then
    echo "STOP: no active white-label owner record was found."
    echo "Convert/create the white-label owner first, then run this installer."
    exit 1
fi

mkdir -p "$BACKUP"
EXISTING_LIST="$BACKUP/existing.list"
NEW_LIST="$BACKUP/new.list"
: > "$EXISTING_LIST"
: > "$NEW_LIST"

TARGETS=(
    "routes/web.php"
    "app/Http/Controllers/Reseller/AuthController.php"
    "app/Http/Middleware/EnsureWhiteLabelAdmin.php"
    "app/Http/Controllers/WhiteLabel/Admin/TenantController.php"
    "app/Http/Controllers/WhiteLabel/Admin/DashboardController.php"
    "app/Http/Controllers/WhiteLabel/Admin/ClientController.php"
    "app/Http/Controllers/WhiteLabel/Admin/ResellerController.php"
    "app/Http/Controllers/WhiteLabel/Admin/WalletController.php"
    "app/Http/Controllers/WhiteLabel/Admin/SettingsController.php"
    "routes/white_label_admin.php"
    "resources/js/Layouts/WhiteLabelAdminLayout.jsx"
    "resources/js/Pages/WhiteLabel/Admin/Dashboard.jsx"
    "resources/js/Pages/WhiteLabel/Admin/Clients/Index.jsx"
    "resources/js/Pages/WhiteLabel/Admin/Clients/Show.jsx"
    "resources/js/Pages/WhiteLabel/Admin/Resellers/Index.jsx"
    "resources/js/Pages/WhiteLabel/Admin/Wallet.jsx"
    "resources/js/Pages/WhiteLabel/Admin/Settings.jsx"
)

for f in "${TARGETS[@]}"; do
    if [ -f "$f" ]; then
        mkdir -p "$BACKUP/$(dirname "$f")"
        \cp -a "$f" "$BACKUP/$f"
        echo "$f" >> "$EXISTING_LIST"
    else
        echo "$f" >> "$NEW_LIST"
    fi
done

if [ -d public/build ]; then
    \cp -a public/build "$BACKUP/public-build"
fi

rollback() {
    set +e
    echo
    echo "INSTALL FAILED - restoring backup..."

    while IFS= read -r f; do
        [ -n "$f" ] || continue
        if [ -f "$BACKUP/$f" ]; then
            mkdir -p "$(dirname "$f")"
            \cp -af "$BACKUP/$f" "$f"
        fi
    done < "$EXISTING_LIST"

    while IFS= read -r f; do
        [ -n "$f" ] || continue
        rm -f "$f"
    done < "$NEW_LIST"

    if [ -d "$BACKUP/public-build" ]; then
        rm -rf public/build
        \cp -a "$BACKUP/public-build" public/build
    fi

    php artisan optimize:clear >/dev/null 2>&1 || true

    echo "Rollback complete."
    echo "Backup: $BACKUP"
}

trap rollback ERR

APP_USER="$(stat -c '%U' artisan)"
APP_GROUP="$(stat -c '%G' artisan)"

echo "Application owner: $APP_USER:$APP_GROUP"
echo
echo "===== INSTALLING TENANT-SAFE WHITE-LABEL ADMIN ====="

mkdir -p "$(dirname 'app/Http/Middleware/EnsureWhiteLabelAdmin.php')"
cat > 'app/Http/Middleware/EnsureWhiteLabelAdmin.php' <<'PHP_1_WLADMIN'
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureWhiteLabelAdmin
{
    public function handle(Request $request, Closure $next): Response
    {
        $user = $request->user('reseller');
        $reseller = $user?->reseller;

        abort_unless(
            $user
            && $user->status === 'active'
            && $reseller
            && $reseller->isActive()
            && ! $reseller->parent_reseller_id
            && (bool) ($reseller->white_label_enabled ?? false),
            403,
            'White-label administrator access required.'
        );

        $domainOwnerId = $request->attributes->get('white_label_owner_id');

        if (
            $domainOwnerId
            && (int) $domainOwnerId !== (int) $reseller->id
        ) {
            abort(403, 'This account does not belong to this white-label portal.');
        }

        $request->attributes->set('white_label_admin_owner', $reseller);

        return $next($request);
    }
}
PHP_1_WLADMIN

mkdir -p "$(dirname 'app/Http/Controllers/WhiteLabel/Admin/TenantController.php')"
cat > 'app/Http/Controllers/WhiteLabel/Admin/TenantController.php' <<'PHP_2_WLADMIN'
<?php

namespace App\Http\Controllers\WhiteLabel\Admin;

use App\Http\Controllers\Controller;
use App\Models\BillingFixedCharge;
use App\Models\Client;
use App\Models\Reseller;
use App\Models\Wallet;
use App\Models\WalletTransaction;
use App\Services\Billing\BillingMoney;
use App\Services\Billing\WalletService;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use RuntimeException;

abstract class TenantController extends Controller
{
    protected function owner(Request $request): Reseller
    {
        $owner = $request->attributes->get('white_label_admin_owner')
            ?: $request->user('reseller')?->reseller;

        abort_unless(
            $owner
            && ! $owner->parent_reseller_id
            && (bool) ($owner->white_label_enabled ?? false),
            403
        );

        return $owner->loadMissing(['wallet', 'branding', 'domains']);
    }

    protected function treeIds(Reseller $owner): array
    {
        $ids = [(int) $owner->id];
        $frontier = [(int) $owner->id];

        for ($depth = 0; $depth < 20 && $frontier; $depth++) {
            $children = Reseller::query()
                ->whereIn('parent_reseller_id', $frontier)
                ->pluck('id')
                ->map(fn ($id) => (int) $id)
                ->all();

            $children = array_values(array_diff($children, $ids));

            if (! $children) {
                break;
            }

            $ids = array_values(array_unique(array_merge($ids, $children)));
            $frontier = $children;
        }

        return $ids;
    }

    protected function scopedClient(Reseller $owner, int $clientId): Client
    {
        return Client::query()
            ->whereKey($clientId)
            ->whereIn('reseller_id', $this->treeIds($owner))
            ->firstOrFail();
    }

    protected function scopedChildReseller(
        Reseller $owner,
        int $resellerId
    ): Reseller {
        abort_if($resellerId === (int) $owner->id, 404);

        $reseller = Reseller::query()->findOrFail($resellerId);

        abort_unless($reseller->isWithinTreeOf((int) $owner->id), 404);

        /*
         * White-label administrators may manage ordinary resellers in
         * their own tree, but never another white-label owner.
         */
        abort_if(
            ! $reseller->parent_reseller_id
            || (bool) ($reseller->white_label_enabled ?? false),
            403,
            'Nested white-label panels are not permitted.'
        );

        return $reseller;
    }

    protected function currency(Reseller $owner): string
    {
        return strtoupper($owner->currency_code ?: 'INR');
    }

    protected function wallet(Reseller $owner): Wallet
    {
        return app(WalletService::class)->getOrCreate(
            Wallet::OWNER_RESELLER,
            (int) $owner->id,
            $this->currency($owner)
        );
    }

    protected function activationFeeMicros(
        Reseller $owner,
        string $code
    ): int {
        $currency = $this->currency($owner);

        $charge = BillingFixedCharge::query()
            ->where('scope_type', 'reseller')
            ->where('scope_id', $owner->id)
            ->where('charge_code', $code)
            ->where('currency_code', $currency)
            ->where('is_active', true)
            ->first();

        if (! $charge) {
            $charge = BillingFixedCharge::query()
                ->where('scope_type', 'platform')
                ->where('scope_id', 0)
                ->where('charge_code', $code)
                ->where('currency_code', $currency)
                ->where('is_active', true)
                ->first();
        }

        return max(0, (int) ($charge?->amount_micros ?? 0));
    }

    protected function assertCreationCredit(
        Reseller $owner,
        int $requiredMicros
    ): Wallet {
        $wallet = $this->wallet($owner)->fresh();

        if ($wallet->status !== Wallet::STATUS_ACTIVE) {
            throw new RuntimeException(
                'Your white-label wallet is not active. Contact the platform administrator.'
            );
        }

        /*
         * Requested business rule:
         * a white-label owner must have wallet credit before creating
         * a client or reseller, even when the configured activation fee is zero.
         */
        if ((int) $wallet->balance_micros <= 0) {
            throw new RuntimeException(
                'Wallet credit is required before you can create clients or resellers.'
            );
        }

        if ((int) $wallet->balance_micros < $requiredMicros) {
            throw new RuntimeException(
                'Insufficient white-label wallet balance for this operation.'
            );
        }

        return $wallet;
    }

    protected function debitActivation(
        Reseller $owner,
        int $amountMicros,
        string $code,
        string $referenceType,
        string $referenceId,
        int $actorId
    ): void {
        if ($amountMicros <= 0) {
            return;
        }

        app(WalletService::class)->debit(
            Wallet::OWNER_RESELLER,
            (int) $owner->id,
            $amountMicros,
            'white_label_'.$code,
            str_replace('_', ' ', ucfirst($code)).' charge',
            $referenceType,
            $referenceId,
            'wl-'.$code.'-'.$owner->id.'-'.$referenceId,
            'reseller_user',
            $actorId,
            [
                'white_label_owner_id' => (int) $owner->id,
                'charge_code' => $code,
            ],
            $this->currency($owner)
        );
    }

    protected function transferFromOwner(
        Reseller $owner,
        string $toOwnerType,
        int $toOwnerId,
        int $amountMicros,
        string $type,
        string $description,
        int $actorId,
        array $metadata = []
    ): void {
        if ($amountMicros <= 0) {
            return;
        }

        app(WalletService::class)->transfer(
            Wallet::OWNER_RESELLER,
            (int) $owner->id,
            $toOwnerType,
            $toOwnerId,
            $amountMicros,
            $type,
            $description,
            'wl-transfer-'.Str::uuid(),
            'reseller_user',
            $actorId,
            array_merge(
                ['white_label_owner_id' => (int) $owner->id],
                $metadata
            ),
            $this->currency($owner)
        );
    }

    protected function transferToOwner(
        Reseller $owner,
        string $fromOwnerType,
        int $fromOwnerId,
        int $amountMicros,
        string $type,
        string $description,
        int $actorId,
        array $metadata = []
    ): void {
        if ($amountMicros <= 0) {
            return;
        }

        app(WalletService::class)->transfer(
            $fromOwnerType,
            $fromOwnerId,
            Wallet::OWNER_RESELLER,
            (int) $owner->id,
            $amountMicros,
            $type,
            $description,
            'wl-reclaim-'.Str::uuid(),
            'reseller_user',
            $actorId,
            array_merge(
                ['white_label_owner_id' => (int) $owner->id],
                $metadata
            ),
            $this->currency($owner)
        );
    }

    protected function shell(
        Request $request,
        Reseller $owner
    ): array {
        $wallet = $this->wallet($owner)->fresh();
        $branding = $owner->branding;

        return [
            'owner' => [
                'id' => (int) $owner->id,
                'name' => $owner->name,
                'email' => $owner->email,
                'currency_code' => $this->currency($owner),
                'white_label_enabled' => true,
                'brand_name' => $branding?->brand_name,
            ],
            'whiteLabelUser' => [
                'id' => (int) $request->user('reseller')->id,
                'name' => $request->user('reseller')->name,
                'email' => $request->user('reseller')->email,
            ],
            'walletSummary' => [
                'balance' => BillingMoney::fromMicros(
                    (int) $wallet->balance_micros
                ),
                'balance_micros' => (int) $wallet->balance_micros,
                'currency_code' => $wallet->currency_code,
                'status' => $wallet->status,
            ],
        ];
    }

    protected function recentTransactions(
        Wallet $wallet,
        int $limit = 100
    ): array {
        return WalletTransaction::query()
            ->where('wallet_id', $wallet->id)
            ->latest('id')
            ->limit($limit)
            ->get()
            ->map(fn (WalletTransaction $tx) => [
                'id' => $tx->id,
                'direction' => $tx->direction,
                'type' => $tx->type,
                'amount' => BillingMoney::fromMicros((int) $tx->amount_micros),
                'balance_before' => BillingMoney::fromMicros(
                    (int) $tx->balance_before_micros
                ),
                'balance_after' => BillingMoney::fromMicros(
                    (int) $tx->balance_after_micros
                ),
                'description' => $tx->description,
                'created_at' => $tx->created_at?->toIso8601String(),
            ])
            ->values()
            ->all();
    }
}
PHP_2_WLADMIN

mkdir -p "$(dirname 'app/Http/Controllers/WhiteLabel/Admin/DashboardController.php')"
cat > 'app/Http/Controllers/WhiteLabel/Admin/DashboardController.php' <<'PHP_3_WLADMIN'
<?php

namespace App\Http\Controllers\WhiteLabel\Admin;

use App\Models\Client;
use App\Models\Reseller;
use App\Models\Wallet;
use App\Services\Billing\BillingMoney;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

class DashboardController extends TenantController
{
    public function __invoke(Request $request): Response
    {
        $owner = $this->owner($request);
        $treeIds = $this->treeIds($owner);
        $childIds = array_values(array_diff($treeIds, [(int) $owner->id]));

        $clientCount = Client::query()
            ->whereIn('reseller_id', $treeIds)
            ->count();

        $resellerCount = count($childIds);

        $clientWalletMicros = Wallet::query()
            ->where('owner_type', Wallet::OWNER_CLIENT)
            ->whereIn(
                'owner_id',
                Client::query()
                    ->whereIn('reseller_id', $treeIds)
                    ->select('id')
            )
            ->sum('balance_micros');

        $childWalletMicros = $childIds
            ? Wallet::query()
                ->where('owner_type', Wallet::OWNER_RESELLER)
                ->whereIn('owner_id', $childIds)
                ->sum('balance_micros')
            : 0;

        $wallet = $this->wallet($owner)->fresh();

        return Inertia::render('WhiteLabel/Admin/Dashboard', array_merge(
            $this->shell($request, $owner),
            [
                'stats' => [
                    'clients' => $clientCount,
                    'resellers' => $resellerCount,
                    'client_wallet_total' => BillingMoney::fromMicros(
                        (int) $clientWalletMicros
                    ),
                    'reseller_wallet_total' => BillingMoney::fromMicros(
                        (int) $childWalletMicros
                    ),
                ],
                'activationFees' => [
                    'client' => BillingMoney::fromMicros(
                        $this->activationFeeMicros($owner, 'client_activation')
                    ),
                    'reseller' => BillingMoney::fromMicros(
                        $this->activationFeeMicros($owner, 'reseller_activation')
                    ),
                ],
                'recentTransactions' => $this->recentTransactions($wallet, 12),
            ]
        ));
    }
}
PHP_3_WLADMIN

mkdir -p "$(dirname 'app/Http/Controllers/WhiteLabel/Admin/ClientController.php')"
cat > 'app/Http/Controllers/WhiteLabel/Admin/ClientController.php' <<'PHP_4_WLADMIN'
<?php

namespace App\Http\Controllers\WhiteLabel\Admin;

use App\Models\Client;
use App\Models\User;
use App\Models\Wallet;
use App\Services\Billing\BillingMoney;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
use Inertia\Response;
use RuntimeException;
use Throwable;

class ClientController extends TenantController
{
    public function index(Request $request): Response
    {
        $owner = $this->owner($request);
        $treeIds = $this->treeIds($owner);

        $search = trim((string) $request->get('search', ''));

        $clients = Client::query()
            ->with(['wallet', 'reseller:id,name'])
            ->withCount('users')
            ->whereIn('reseller_id', $treeIds)
            ->when($search !== '', function ($query) use ($search) {
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%");
                });
            })
            ->orderBy('name')
            ->paginate(20)
            ->withQueryString()
            ->through(fn (Client $client) => [
                'id' => $client->id,
                'name' => $client->name,
                'email' => $client->email,
                'phone' => $client->phone,
                'status' => $client->status,
                'reseller' => $client->reseller?->name,
                'users_count' => $client->users_count,
                'wallet_balance' => BillingMoney::fromMicros(
                    (int) ($client->wallet?->balance_micros ?? 0)
                ),
            ]);

        return Inertia::render('WhiteLabel/Admin/Clients/Index', array_merge(
            $this->shell($request, $owner),
            [
                'clients' => $clients,
                'filters' => ['search' => $search],
                'activationFee' => BillingMoney::fromMicros(
                    $this->activationFeeMicros($owner, 'client_activation')
                ),
            ]
        ));
    }

    public function store(Request $request): RedirectResponse
    {
        $owner = $this->owner($request);
        $actor = $request->user('reseller');

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['nullable', 'email', 'max:255'],
            'phone' => ['nullable', 'string', 'max:64'],
            'address' => ['nullable', 'string', 'max:2000'],
            'initial_credit' => ['nullable', 'regex:/^\d+(?:\.\d{1,6})?$/'],

            'admin_name' => [
                'nullable',
                'string',
                'max:255',
                'required_with:admin_email',
            ],
            'admin_email' => [
                'nullable',
                'email',
                'max:255',
                Rule::unique('users', 'email'),
            ],
            'admin_password' => [
                'nullable',
                'string',
                'min:8',
                'max:255',
                'required_with:admin_email',
            ],
        ]);

        $initialMicros = BillingMoney::toMicros(
            $validated['initial_credit'] ?? '0'
        );

        $feeMicros = $this->activationFeeMicros(
            $owner,
            'client_activation'
        );

        try {
            $this->assertCreationCredit(
                $owner,
                $feeMicros + $initialMicros
            );

            DB::transaction(function () use (
                $owner,
                $actor,
                $validated,
                $feeMicros,
                $initialMicros
            ) {
                $client = Client::create([
                    'reseller_id' => $owner->id,
                    'name' => $validated['name'],
                    'email' => $validated['email'] ?? null,
                    'phone' => $validated['phone'] ?? null,
                    'address' => $validated['address'] ?? null,
                    'status' => Client::STATUS_ACTIVE,
                    'base_currency' => $this->currency($owner),
                ]);

                app(\App\Services\Billing\WalletService::class)->getOrCreate(
                    Wallet::OWNER_CLIENT,
                    (int) $client->id,
                    $this->currency($owner)
                );

                if (! empty($validated['admin_email'])) {
                    $client->users()->create([
                        'name' => $validated['admin_name'],
                        'email' => strtolower($validated['admin_email']),
                        'password' => $validated['admin_password'],
                        'role' => User::ROLE_CLIENT,
                        'client_id' => $client->id,
                        'client_role' => User::CLIENT_ROLE_ADMINISTRATOR,
                        'status' => User::STATUS_ACTIVE,
                        'email_verified_at' => now(),
                    ]);
                }

                $this->debitActivation(
                    $owner,
                    $feeMicros,
                    'client_activation',
                    'client',
                    (string) $client->id,
                    (int) $actor->id
                );

                $this->transferFromOwner(
                    $owner,
                    Wallet::OWNER_CLIENT,
                    (int) $client->id,
                    $initialMicros,
                    'white_label_client_initial_credit',
                    'Initial client wallet credit.',
                    (int) $actor->id,
                    ['client_id' => (int) $client->id]
                );
            }, 3);
        } catch (RuntimeException $e) {
            return back()->withErrors(['wallet' => $e->getMessage()])->withInput();
        } catch (Throwable $e) {
            report($e);

            return back()->withErrors([
                'client' => 'Client could not be created. No wallet debit was kept.',
            ])->withInput();
        }

        return back()->with('success', 'Client created successfully.');
    }

    public function show(Request $request, Client $client): Response
    {
        $owner = $this->owner($request);
        $client = $this->scopedClient($owner, (int) $client->id);
        $client->load(['wallet', 'users', 'reseller:id,name']);

        return Inertia::render('WhiteLabel/Admin/Clients/Show', array_merge(
            $this->shell($request, $owner),
            [
                'client' => [
                    'id' => $client->id,
                    'name' => $client->name,
                    'email' => $client->email,
                    'phone' => $client->phone,
                    'address' => $client->address,
                    'status' => $client->status,
                    'reseller' => $client->reseller?->name,
                    'wallet_balance' => BillingMoney::fromMicros(
                        (int) ($client->wallet?->balance_micros ?? 0)
                    ),
                    'users' => $client->users
                        ->sortBy('name')
                        ->values()
                        ->map(fn (User $user) => [
                            'id' => $user->id,
                            'name' => $user->name,
                            'email' => $user->email,
                            'client_role' => $user->client_role,
                            'status' => $user->status,
                        ]),
                ],
            ]
        ));
    }

    public function update(
        Request $request,
        Client $client
    ): RedirectResponse {
        $owner = $this->owner($request);
        $client = $this->scopedClient($owner, (int) $client->id);

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['nullable', 'email', 'max:255'],
            'phone' => ['nullable', 'string', 'max:64'],
            'address' => ['nullable', 'string', 'max:2000'],
            'status' => ['required', 'in:active,inactive'],
        ]);

        $client->update($validated);

        return back()->with('success', 'Client updated.');
    }

    public function storeUser(
        Request $request,
        Client $client
    ): RedirectResponse {
        $owner = $this->owner($request);
        $client = $this->scopedClient($owner, (int) $client->id);

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('users', 'email'),
            ],
            'password' => ['required', 'string', 'min:8', 'max:255'],
            'client_role' => ['required', 'in:administrator,staff'],
        ]);

        $client->users()->create([
            'name' => $validated['name'],
            'email' => strtolower($validated['email']),
            'password' => $validated['password'],
            'role' => User::ROLE_CLIENT,
            'client_id' => $client->id,
            'client_role' => $validated['client_role'],
            'status' => User::STATUS_ACTIVE,
            'email_verified_at' => now(),
        ]);

        return back()->with('success', 'Client user added.');
    }

    public function updateUser(
        Request $request,
        Client $client,
        User $user
    ): RedirectResponse {
        $owner = $this->owner($request);
        $client = $this->scopedClient($owner, (int) $client->id);

        abort_unless((int) $user->client_id === (int) $client->id, 404);

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('users', 'email')->ignore($user->id),
            ],
            'client_role' => ['required', 'in:administrator,staff'],
            'status' => ['required', 'in:active,inactive'],
            'password' => ['nullable', 'string', 'min:8', 'max:255'],
        ]);

        $user->fill([
            'name' => $validated['name'],
            'email' => strtolower($validated['email']),
            'client_role' => $validated['client_role'],
            'status' => $validated['status'],
        ]);

        if (! empty($validated['password'])) {
            $user->password = $validated['password'];
        }

        $user->save();

        return back()->with('success', 'Client user updated.');
    }

    public function destroyUser(
        Request $request,
        Client $client,
        User $user
    ): RedirectResponse {
        $owner = $this->owner($request);
        $client = $this->scopedClient($owner, (int) $client->id);

        abort_unless((int) $user->client_id === (int) $client->id, 404);

        $adminCount = $client->users()
            ->where('client_role', User::CLIENT_ROLE_ADMINISTRATOR)
            ->count();

        if (
            $user->client_role === User::CLIENT_ROLE_ADMINISTRATOR
            && $adminCount <= 1
        ) {
            return back()->withErrors([
                'user' => 'Cannot remove the last client administrator.',
            ]);
        }

        $user->delete();

        return back()->with('success', 'Client user removed.');
    }

    public function fund(
        Request $request,
        Client $client
    ): RedirectResponse {
        $owner = $this->owner($request);
        $client = $this->scopedClient($owner, (int) $client->id);

        $validated = $request->validate([
            'amount' => ['required', 'regex:/^\d+(?:\.\d{1,6})?$/'],
        ]);

        $amount = BillingMoney::toMicros($validated['amount']);

        try {
            $this->transferFromOwner(
                $owner,
                Wallet::OWNER_CLIENT,
                (int) $client->id,
                $amount,
                'white_label_client_funding',
                'Credit allocated by white-label administrator.',
                (int) $request->user('reseller')->id,
                ['client_id' => (int) $client->id]
            );
        } catch (RuntimeException $e) {
            return back()->withErrors(['wallet' => $e->getMessage()]);
        }

        return back()->with('success', 'Client wallet funded.');
    }

    public function reclaim(
        Request $request,
        Client $client
    ): RedirectResponse {
        $owner = $this->owner($request);
        $client = $this->scopedClient($owner, (int) $client->id);

        $validated = $request->validate([
            'amount' => ['required', 'regex:/^\d+(?:\.\d{1,6})?$/'],
        ]);

        $amount = BillingMoney::toMicros($validated['amount']);

        try {
            $this->transferToOwner(
                $owner,
                Wallet::OWNER_CLIENT,
                (int) $client->id,
                $amount,
                'white_label_client_reclaim',
                'Credit reclaimed by white-label administrator.',
                (int) $request->user('reseller')->id,
                ['client_id' => (int) $client->id]
            );
        } catch (RuntimeException $e) {
            return back()->withErrors(['wallet' => $e->getMessage()]);
        }

        return back()->with('success', 'Client credit reclaimed.');
    }
}
PHP_4_WLADMIN

mkdir -p "$(dirname 'app/Http/Controllers/WhiteLabel/Admin/ResellerController.php')"
cat > 'app/Http/Controllers/WhiteLabel/Admin/ResellerController.php' <<'PHP_5_WLADMIN'
<?php

namespace App\Http\Controllers\WhiteLabel\Admin;

use App\Models\Reseller;
use App\Models\ResellerUser;
use App\Models\Wallet;
use App\Services\Billing\BillingMoney;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
use Inertia\Response;
use RuntimeException;
use Throwable;

class ResellerController extends TenantController
{
    public function index(Request $request): Response
    {
        $owner = $this->owner($request);
        $treeIds = $this->treeIds($owner);

        $resellers = Reseller::query()
            ->with(['wallet', 'users:id,reseller_id,name,email,role,status'])
            ->withCount('clients')
            ->whereIn('id', array_diff($treeIds, [(int) $owner->id]))
            ->orderBy('name')
            ->get()
            ->map(fn (Reseller $reseller) => [
                'id' => $reseller->id,
                'name' => $reseller->name,
                'email' => $reseller->email,
                'phone' => $reseller->phone,
                'status' => $reseller->status,
                'clients_count' => $reseller->clients_count,
                'wallet_balance' => BillingMoney::fromMicros(
                    (int) ($reseller->wallet?->balance_micros ?? 0)
                ),
                'users' => $reseller->users->map(fn (ResellerUser $user) => [
                    'id' => $user->id,
                    'name' => $user->name,
                    'email' => $user->email,
                    'role' => $user->role,
                    'status' => $user->status,
                ])->values(),
            ])
            ->values();

        return Inertia::render('WhiteLabel/Admin/Resellers/Index', array_merge(
            $this->shell($request, $owner),
            [
                'resellers' => $resellers,
                'activationFee' => BillingMoney::fromMicros(
                    $this->activationFeeMicros($owner, 'reseller_activation')
                ),
            ]
        ));
    }

    public function store(Request $request): RedirectResponse
    {
        $owner = $this->owner($request);
        $actor = $request->user('reseller');

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email', 'max:255'],
            'phone' => ['nullable', 'string', 'max:64'],
            'admin_name' => ['required', 'string', 'max:255'],
            'admin_email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('reseller_users', 'email'),
            ],
            'password' => ['required', 'string', 'min:8', 'max:255'],
            'initial_credit' => ['nullable', 'regex:/^\d+(?:\.\d{1,6})?$/'],
        ]);

        $initialMicros = BillingMoney::toMicros(
            $validated['initial_credit'] ?? '0'
        );

        $feeMicros = $this->activationFeeMicros(
            $owner,
            'reseller_activation'
        );

        try {
            $this->assertCreationCredit(
                $owner,
                $feeMicros + $initialMicros
            );

            DB::transaction(function () use (
                $owner,
                $actor,
                $validated,
                $feeMicros,
                $initialMicros
            ) {
                $reseller = Reseller::create([
                    'parent_reseller_id' => $owner->id,
                    'name' => $validated['name'],
                    'email' => strtolower($validated['email']),
                    'phone' => $validated['phone'] ?? null,
                    'status' => Reseller::STATUS_ACTIVE,
                    'currency_code' => $this->currency($owner),
                    'support_email' => strtolower($validated['email']),
                    'support_phone' => $validated['phone'] ?? null,
                ]);

                /*
                 * Hard safety: a white-label owner can create only ordinary
                 * resellers. There is no request field that can override this.
                 */
                $reseller->forceFill([
                    'white_label_enabled' => false,
                    'parent_reseller_id' => $owner->id,
                ])->save();

                app(\App\Services\Billing\WalletService::class)->getOrCreate(
                    Wallet::OWNER_RESELLER,
                    (int) $reseller->id,
                    $this->currency($owner)
                );

                ResellerUser::create([
                    'reseller_id' => $reseller->id,
                    'name' => $validated['admin_name'],
                    'email' => strtolower($validated['admin_email']),
                    'password' => $validated['password'],
                    'role' => 'administrator',
                    'status' => 'active',
                ]);

                $this->debitActivation(
                    $owner,
                    $feeMicros,
                    'reseller_activation',
                    'reseller',
                    (string) $reseller->id,
                    (int) $actor->id
                );

                $this->transferFromOwner(
                    $owner,
                    Wallet::OWNER_RESELLER,
                    (int) $reseller->id,
                    $initialMicros,
                    'white_label_reseller_initial_credit',
                    'Initial reseller wallet credit.',
                    (int) $actor->id,
                    ['child_reseller_id' => (int) $reseller->id]
                );
            }, 3);
        } catch (RuntimeException $e) {
            return back()->withErrors(['wallet' => $e->getMessage()])->withInput();
        } catch (Throwable $e) {
            report($e);

            return back()->withErrors([
                'reseller' => 'Reseller could not be created. No wallet debit was kept.',
            ])->withInput();
        }

        return back()->with('success', 'Reseller created successfully.');
    }

    public function update(
        Request $request,
        Reseller $reseller
    ): RedirectResponse {
        $owner = $this->owner($request);
        $reseller = $this->scopedChildReseller(
            $owner,
            (int) $reseller->id
        );

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['nullable', 'email', 'max:255'],
            'phone' => ['nullable', 'string', 'max:64'],
            'status' => ['required', 'in:active,inactive'],
        ]);

        $reseller->fill($validated);
        $reseller->forceFill(['white_label_enabled' => false]);
        $reseller->save();

        return back()->with('success', 'Reseller updated.');
    }

    public function storeUser(
        Request $request,
        Reseller $reseller
    ): RedirectResponse {
        $owner = $this->owner($request);
        $reseller = $this->scopedChildReseller(
            $owner,
            (int) $reseller->id
        );

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('reseller_users', 'email'),
            ],
            'password' => ['required', 'string', 'min:8', 'max:255'],
        ]);

        ResellerUser::create([
            'reseller_id' => $reseller->id,
            'name' => $validated['name'],
            'email' => strtolower($validated['email']),
            'password' => $validated['password'],
            'role' => 'administrator',
            'status' => 'active',
        ]);

        return back()->with('success', 'Reseller administrator added.');
    }

    public function fund(
        Request $request,
        Reseller $reseller
    ): RedirectResponse {
        $owner = $this->owner($request);
        $reseller = $this->scopedChildReseller(
            $owner,
            (int) $reseller->id
        );

        $validated = $request->validate([
            'amount' => ['required', 'regex:/^\d+(?:\.\d{1,6})?$/'],
        ]);

        $amount = BillingMoney::toMicros($validated['amount']);

        try {
            $this->transferFromOwner(
                $owner,
                Wallet::OWNER_RESELLER,
                (int) $reseller->id,
                $amount,
                'white_label_reseller_funding',
                'Credit allocated by white-label administrator.',
                (int) $request->user('reseller')->id,
                ['child_reseller_id' => (int) $reseller->id]
            );
        } catch (RuntimeException $e) {
            return back()->withErrors(['wallet' => $e->getMessage()]);
        }

        return back()->with('success', 'Reseller wallet funded.');
    }

    public function reclaim(
        Request $request,
        Reseller $reseller
    ): RedirectResponse {
        $owner = $this->owner($request);
        $reseller = $this->scopedChildReseller(
            $owner,
            (int) $reseller->id
        );

        $validated = $request->validate([
            'amount' => ['required', 'regex:/^\d+(?:\.\d{1,6})?$/'],
        ]);

        $amount = BillingMoney::toMicros($validated['amount']);

        try {
            $this->transferToOwner(
                $owner,
                Wallet::OWNER_RESELLER,
                (int) $reseller->id,
                $amount,
                'white_label_reseller_reclaim',
                'Credit reclaimed by white-label administrator.',
                (int) $request->user('reseller')->id,
                ['child_reseller_id' => (int) $reseller->id]
            );
        } catch (RuntimeException $e) {
            return back()->withErrors(['wallet' => $e->getMessage()]);
        }

        return back()->with('success', 'Reseller credit reclaimed.');
    }
}
PHP_5_WLADMIN

mkdir -p "$(dirname 'app/Http/Controllers/WhiteLabel/Admin/WalletController.php')"
cat > 'app/Http/Controllers/WhiteLabel/Admin/WalletController.php' <<'PHP_6_WLADMIN'
<?php

namespace App\Http\Controllers\WhiteLabel\Admin;

use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

class WalletController extends TenantController
{
    public function index(Request $request): Response
    {
        $owner = $this->owner($request);
        $wallet = $this->wallet($owner)->fresh();

        return Inertia::render('WhiteLabel/Admin/Wallet', array_merge(
            $this->shell($request, $owner),
            [
                'transactions' => $this->recentTransactions($wallet, 150),
            ]
        ));
    }
}
PHP_6_WLADMIN

mkdir -p "$(dirname 'app/Http/Controllers/WhiteLabel/Admin/SettingsController.php')"
cat > 'app/Http/Controllers/WhiteLabel/Admin/SettingsController.php' <<'PHP_7_WLADMIN'
<?php

namespace App\Http\Controllers\WhiteLabel\Admin;

use App\Models\ResellerBranding;
use App\Models\ResellerUser;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
use Inertia\Response;

class SettingsController extends TenantController
{
    public function index(Request $request): Response
    {
        $owner = $this->owner($request);
        $branding = $owner->branding;

        return Inertia::render('WhiteLabel/Admin/Settings', array_merge(
            $this->shell($request, $owner),
            [
                'brandingSettings' => [
                    'brand_name' => $branding?->brand_name,
                    'primary_color' => $branding?->primary_color ?: '#467235',
                    'tagline' => $branding?->tagline,
                    'support_email' => $branding?->support_email,
                    'support_phone' => $branding?->support_phone,
                    'login_heading' => $branding?->login_heading,
                ],
                'teamUsers' => $owner->users()
                    ->orderBy('name')
                    ->get()
                    ->map(fn (ResellerUser $user) => [
                        'id' => $user->id,
                        'name' => $user->name,
                        'email' => $user->email,
                        'role' => $user->role,
                        'status' => $user->status,
                    ])
                    ->values(),
            ]
        ));
    }

    public function updateBranding(Request $request): RedirectResponse
    {
        $owner = $this->owner($request);

        $validated = $request->validate([
            'brand_name' => ['nullable', 'string', 'max:255'],
            'primary_color' => [
                'nullable',
                'regex:/^#[0-9A-Fa-f]{6}$/',
            ],
            'tagline' => ['nullable', 'string', 'max:255'],
            'support_email' => ['nullable', 'email', 'max:255'],
            'support_phone' => ['nullable', 'string', 'max:64'],
            'login_heading' => ['nullable', 'string', 'max:255'],
        ]);

        ResellerBranding::query()->updateOrCreate(
            ['reseller_id' => $owner->id],
            $validated
        );

        return back()->with('success', 'White-label branding updated.');
    }

    public function storeTeamUser(Request $request): RedirectResponse
    {
        $owner = $this->owner($request);

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('reseller_users', 'email'),
            ],
            'password' => ['required', 'string', 'min:8', 'max:255'],
        ]);

        ResellerUser::create([
            'reseller_id' => $owner->id,
            'name' => $validated['name'],
            'email' => strtolower($validated['email']),
            'password' => $validated['password'],
            'role' => 'administrator',
            'status' => 'active',
        ]);

        return back()->with('success', 'White-label administrator added.');
    }

    public function updateTeamUser(
        Request $request,
        ResellerUser $resellerUser
    ): RedirectResponse {
        $owner = $this->owner($request);

        abort_unless(
            (int) $resellerUser->reseller_id === (int) $owner->id,
            404
        );

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => [
                'required',
                'email',
                'max:255',
                Rule::unique('reseller_users', 'email')
                    ->ignore($resellerUser->id),
            ],
            'status' => ['required', 'in:active,inactive'],
            'password' => ['nullable', 'string', 'min:8', 'max:255'],
        ]);

        if (
            (int) $resellerUser->id
                === (int) $request->user('reseller')->id
            && $validated['status'] !== 'active'
        ) {
            return back()->withErrors([
                'team' => 'You cannot deactivate your own current login.',
            ]);
        }

        $resellerUser->fill([
            'name' => $validated['name'],
            'email' => strtolower($validated['email']),
            'status' => $validated['status'],
        ]);

        if (! empty($validated['password'])) {
            $resellerUser->password = $validated['password'];
        }

        $resellerUser->save();

        return back()->with('success', 'Administrator updated.');
    }
}
PHP_7_WLADMIN

mkdir -p "$(dirname 'routes/white_label_admin.php')"
cat > 'routes/white_label_admin.php' <<'PHP_8_WLADMIN'
<?php

use App\Http\Controllers\WhiteLabel\Admin\ClientController;
use App\Http\Controllers\WhiteLabel\Admin\DashboardController;
use App\Http\Controllers\WhiteLabel\Admin\ResellerController;
use App\Http\Controllers\WhiteLabel\Admin\SettingsController;
use App\Http\Controllers\WhiteLabel\Admin\WalletController;
use App\Http\Middleware\EnsureResellerAuthenticated;
use App\Http\Middleware\EnsureWhiteLabelAdmin;
use Illuminate\Support\Facades\Route;

Route::prefix('reseller/admin')
    ->name('white-label.admin.')
    ->middleware([
        EnsureResellerAuthenticated::class,
        EnsureWhiteLabelAdmin::class,
    ])
    ->group(function () {
        Route::get('/', fn () => redirect()->route(
            'white-label.admin.dashboard'
        ))->name('home');

        Route::get('/dashboard', DashboardController::class)
            ->name('dashboard');

        Route::get('/clients', [ClientController::class, 'index'])
            ->name('clients.index');
        Route::post('/clients', [ClientController::class, 'store'])
            ->name('clients.store');
        Route::get('/clients/{client}', [ClientController::class, 'show'])
            ->name('clients.show');
        Route::put('/clients/{client}', [ClientController::class, 'update'])
            ->name('clients.update');
        Route::post('/clients/{client}/users', [ClientController::class, 'storeUser'])
            ->name('clients.users.store');
        Route::put(
            '/clients/{client}/users/{user}',
            [ClientController::class, 'updateUser']
        )->name('clients.users.update');
        Route::delete(
            '/clients/{client}/users/{user}',
            [ClientController::class, 'destroyUser']
        )->name('clients.users.destroy');
        Route::post('/clients/{client}/fund', [ClientController::class, 'fund'])
            ->name('clients.fund');
        Route::post(
            '/clients/{client}/reclaim',
            [ClientController::class, 'reclaim']
        )->name('clients.reclaim');

        Route::get('/resellers', [ResellerController::class, 'index'])
            ->name('resellers.index');
        Route::post('/resellers', [ResellerController::class, 'store'])
            ->name('resellers.store');
        Route::put(
            '/resellers/{reseller}',
            [ResellerController::class, 'update']
        )->name('resellers.update');
        Route::post(
            '/resellers/{reseller}/users',
            [ResellerController::class, 'storeUser']
        )->name('resellers.users.store');
        Route::post(
            '/resellers/{reseller}/fund',
            [ResellerController::class, 'fund']
        )->name('resellers.fund');
        Route::post(
            '/resellers/{reseller}/reclaim',
            [ResellerController::class, 'reclaim']
        )->name('resellers.reclaim');

        Route::get('/wallet', [WalletController::class, 'index'])
            ->name('wallet.index');

        Route::get('/settings', [SettingsController::class, 'index'])
            ->name('settings.index');
        Route::put(
            '/settings/branding',
            [SettingsController::class, 'updateBranding']
        )->name('settings.branding.update');
        Route::post(
            '/settings/team',
            [SettingsController::class, 'storeTeamUser']
        )->name('settings.team.store');
        Route::put(
            '/settings/team/{resellerUser}',
            [SettingsController::class, 'updateTeamUser']
        )->name('settings.team.update');
    });
PHP_8_WLADMIN

mkdir -p "$(dirname 'resources/js/Layouts/WhiteLabelAdminLayout.jsx')"
cat > 'resources/js/Layouts/WhiteLabelAdminLayout.jsx' <<'JSX_1_WLADMIN'
import { Link, router, usePage } from '@inertiajs/react';
import {
    LayoutDashboard,
    UsersRound,
    Building2,
    WalletCards,
    BadgeDollarSign,
    Settings,
    LogOut,
    ShieldCheck,
    Menu,
    X,
} from 'lucide-react';
import { useState } from 'react';

const nav = [
    ['Dashboard', 'white-label.admin.dashboard', LayoutDashboard],
    ['Clients', 'white-label.admin.clients.index', UsersRound],
    ['Resellers', 'white-label.admin.resellers.index', Building2],
    ['Wallet', 'white-label.admin.wallet.index', WalletCards],
    ['Rates', 'reseller.rates.index', BadgeDollarSign],
    ['Branding & Team', 'white-label.admin.settings.index', Settings],
];

export default function WhiteLabelAdminLayout({
    title = 'White-label Admin',
    owner,
    walletSummary,
    children,
}) {
    const [open, setOpen] = useState(false);
    const { branding = {}, whiteLabelUser = {} } = usePage().props;
    const brandName =
        branding?.app_name ||
        branding?.brand_name ||
        owner?.brand_name ||
        owner?.name ||
        'White-label Admin';

    const current = window.location.pathname;

    const isActive = (name) => {
        const href = route(name);
        try {
            return current.startsWith(new URL(href, window.location.origin).pathname);
        } catch {
            return false;
        }
    };

    const sidebar = (
        <div className="flex h-full flex-col bg-neutral-950 text-white">
            <div className="border-b border-white/10 px-5 py-5">
                <div className="flex items-center gap-3">
                    <div className="grid h-10 w-10 place-items-center rounded-xl bg-white/10">
                        <ShieldCheck className="h-5 w-5" />
                    </div>
                    <div className="min-w-0">
                        <div className="truncate font-semibold">{brandName}</div>
                        <div className="text-xs text-neutral-400">
                            White-label Administration
                        </div>
                    </div>
                </div>
            </div>

            <nav className="flex-1 space-y-1 p-3">
                {nav.map(([label, name, Icon]) => (
                    <Link
                        key={name}
                        href={route(name)}
                        onClick={() => setOpen(false)}
                        className={`flex items-center gap-3 rounded-xl px-3 py-2.5 text-sm transition ${
                            isActive(name)
                                ? 'bg-white text-neutral-950'
                                : 'text-neutral-300 hover:bg-white/10 hover:text-white'
                        }`}
                    >
                        <Icon className="h-4 w-4" />
                        {label}
                    </Link>
                ))}
            </nav>

            <div className="border-t border-white/10 p-4">
                <div className="mb-3 rounded-xl bg-white/5 p-3">
                    <div className="text-xs text-neutral-400">Available Wallet</div>
                    <div className="mt-1 text-lg font-semibold">
                        {walletSummary?.currency_code || owner?.currency_code || 'INR'}{' '}
                        {walletSummary?.balance || '0'}
                    </div>
                </div>
                <button
                    type="button"
                    onClick={() => router.post(route('reseller.logout'))}
                    className="flex w-full items-center gap-2 rounded-xl px-3 py-2 text-sm text-neutral-300 hover:bg-white/10 hover:text-white"
                >
                    <LogOut className="h-4 w-4" />
                    Sign out
                </button>
            </div>
        </div>
    );

    return (
        <div className="min-h-screen bg-neutral-100 text-neutral-900 dark:bg-neutral-950 dark:text-neutral-100">
            <aside className="fixed inset-y-0 left-0 z-40 hidden w-72 lg:block">
                {sidebar}
            </aside>

            {open && (
                <div className="fixed inset-0 z-50 lg:hidden">
                    <button
                        aria-label="Close menu"
                        className="absolute inset-0 bg-black/60"
                        onClick={() => setOpen(false)}
                    />
                    <aside className="relative h-full w-72 shadow-2xl">
                        <button
                            className="absolute right-3 top-3 z-10 rounded-lg bg-white/10 p-2"
                            onClick={() => setOpen(false)}
                        >
                            <X className="h-4 w-4" />
                        </button>
                        {sidebar}
                    </aside>
                </div>
            )}

            <div className="lg:pl-72">
                <header className="sticky top-0 z-30 border-b border-neutral-200 bg-white/95 px-4 py-3 backdrop-blur dark:border-neutral-800 dark:bg-neutral-900/95 sm:px-6">
                    <div className="flex items-center justify-between gap-4">
                        <div className="flex min-w-0 items-center gap-3">
                            <button
                                className="rounded-lg border border-neutral-200 p-2 lg:hidden dark:border-neutral-700"
                                onClick={() => setOpen(true)}
                            >
                                <Menu className="h-4 w-4" />
                            </button>
                            <div className="min-w-0">
                                <h1 className="truncate text-lg font-semibold">{title}</h1>
                                <p className="truncate text-xs text-neutral-500">
                                    {owner?.name}
                                </p>
                            </div>
                        </div>
                        <div className="text-right">
                            <div className="text-sm font-medium">
                                {whiteLabelUser?.name || 'Administrator'}
                            </div>
                            <div className="text-xs text-neutral-500">
                                {whiteLabelUser?.email}
                            </div>
                        </div>
                    </div>
                </header>

                <main className="p-4 sm:p-6 lg:p-8">{children}</main>
            </div>
        </div>
    );
}

export function FlashMessages() {
    const { flash = {}, errors = {} } = usePage().props;
    const firstError = Object.values(errors || {})[0];

    if (!flash.success && !flash.error && !firstError) return null;

    return (
        <div className="mb-6 space-y-2">
            {flash.success && (
                <div className="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800 dark:border-emerald-900 dark:bg-emerald-950/40 dark:text-emerald-300">
                    {flash.success}
                </div>
            )}
            {(flash.error || firstError) && (
                <div className="rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800 dark:border-red-900 dark:bg-red-950/40 dark:text-red-300">
                    {flash.error || firstError}
                </div>
            )}
        </div>
    );
}

export const fieldClass =
    'w-full rounded-xl border border-neutral-300 bg-white px-3 py-2.5 text-sm outline-none transition focus:border-neutral-500 focus:ring-2 focus:ring-neutral-500/10 dark:border-neutral-700 dark:bg-neutral-900';

export const cardClass =
    'rounded-2xl border border-neutral-200 bg-white p-5 shadow-sm dark:border-neutral-800 dark:bg-neutral-900';
JSX_1_WLADMIN

mkdir -p "$(dirname 'resources/js/Pages/WhiteLabel/Admin/Dashboard.jsx')"
cat > 'resources/js/Pages/WhiteLabel/Admin/Dashboard.jsx' <<'JSX_2_WLADMIN'
import { Head, Link } from '@inertiajs/react';
import {
    UsersRound,
    Building2,
    WalletCards,
    ArrowRight,
    ReceiptText,
} from 'lucide-react';
import WhiteLabelAdminLayout, {
    FlashMessages,
    cardClass,
} from '@/Layouts/WhiteLabelAdminLayout';

export default function Dashboard({
    owner,
    walletSummary,
    stats,
    activationFees,
    recentTransactions = [],
}) {
    const cards = [
        ['Clients', stats?.clients ?? 0, UsersRound],
        ['Resellers', stats?.resellers ?? 0, Building2],
        ['Client Wallets', stats?.client_wallet_total ?? '0', WalletCards],
        ['Reseller Wallets', stats?.reseller_wallet_total ?? '0', WalletCards],
    ];

    return (
        <WhiteLabelAdminLayout
            title="Dashboard"
            owner={owner}
            walletSummary={walletSummary}
        >
            <Head title="White-label Admin Dashboard" />
            <FlashMessages />

            <div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
                {cards.map(([label, value, Icon]) => (
                    <div className={cardClass} key={label}>
                        <div className="flex items-center justify-between">
                            <div>
                                <p className="text-xs font-medium uppercase tracking-wide text-neutral-500">
                                    {label}
                                </p>
                                <p className="mt-2 text-2xl font-semibold">{value}</p>
                            </div>
                            <div className="rounded-xl bg-neutral-100 p-3 dark:bg-neutral-800">
                                <Icon className="h-5 w-5" />
                            </div>
                        </div>
                    </div>
                ))}
            </div>

            <div className="mt-6 grid gap-6 xl:grid-cols-3">
                <div className={`${cardClass} xl:col-span-2`}>
                    <div className="mb-4 flex items-center justify-between">
                        <div>
                            <h2 className="font-semibold">Wallet Activity</h2>
                            <p className="text-sm text-neutral-500">
                                White-label master wallet ledger
                            </p>
                        </div>
                        <Link
                            href={route('white-label.admin.wallet.index')}
                            className="inline-flex items-center gap-1 text-sm font-medium"
                        >
                            View all <ArrowRight className="h-4 w-4" />
                        </Link>
                    </div>

                    <div className="overflow-x-auto">
                        <table className="w-full text-left text-sm">
                            <thead className="text-xs uppercase text-neutral-500">
                                <tr>
                                    <th className="pb-3">Type</th>
                                    <th className="pb-3">Direction</th>
                                    <th className="pb-3 text-right">Amount</th>
                                </tr>
                            </thead>
                            <tbody>
                                {recentTransactions.map((tx) => (
                                    <tr
                                        key={tx.id}
                                        className="border-t border-neutral-100 dark:border-neutral-800"
                                    >
                                        <td className="py-3">
                                            <div className="font-medium">{tx.type}</div>
                                            <div className="text-xs text-neutral-500">
                                                {tx.description}
                                            </div>
                                        </td>
                                        <td className="py-3 capitalize">{tx.direction}</td>
                                        <td className="py-3 text-right font-medium">
                                            {walletSummary?.currency_code} {tx.amount}
                                        </td>
                                    </tr>
                                ))}
                                {!recentTransactions.length && (
                                    <tr>
                                        <td colSpan="3" className="py-8 text-center text-neutral-500">
                                            No wallet transactions yet.
                                        </td>
                                    </tr>
                                )}
                            </tbody>
                        </table>
                    </div>
                </div>

                <div className={cardClass}>
                    <div className="mb-4 flex items-center gap-2">
                        <ReceiptText className="h-5 w-5" />
                        <h2 className="font-semibold">Creation Charges</h2>
                    </div>
                    <div className="space-y-4 text-sm">
                        <div className="rounded-xl bg-neutral-50 p-4 dark:bg-neutral-800">
                            <div className="text-neutral-500">Client activation</div>
                            <div className="mt-1 text-xl font-semibold">
                                {walletSummary?.currency_code} {activationFees?.client ?? '0'}
                            </div>
                        </div>
                        <div className="rounded-xl bg-neutral-50 p-4 dark:bg-neutral-800">
                            <div className="text-neutral-500">Reseller activation</div>
                            <div className="mt-1 text-xl font-semibold">
                                {walletSummary?.currency_code} {activationFees?.reseller ?? '0'}
                            </div>
                        </div>
                        <p className="text-xs leading-5 text-neutral-500">
                            Creation is blocked when the white-label wallet has no credit.
                            Configured activation charges and initial credit are deducted
                            from this wallet.
                        </p>
                    </div>
                </div>
            </div>
        </WhiteLabelAdminLayout>
    );
}
JSX_2_WLADMIN

mkdir -p "$(dirname 'resources/js/Pages/WhiteLabel/Admin/Clients/Index.jsx')"
cat > 'resources/js/Pages/WhiteLabel/Admin/Clients/Index.jsx' <<'JSX_3_WLADMIN'
import { Head, Link, router, useForm } from '@inertiajs/react';
import { Search, UserPlus, ArrowRight } from 'lucide-react';
import WhiteLabelAdminLayout, {
    FlashMessages,
    cardClass,
    fieldClass,
} from '@/Layouts/WhiteLabelAdminLayout';

function Pagination({ links = [] }) {
    return (
        <div className="mt-5 flex flex-wrap gap-2">
            {links.map((link, i) =>
                link.url ? (
                    <Link
                        key={i}
                        href={link.url}
                        preserveScroll
                        className={`rounded-lg border px-3 py-1.5 text-sm ${
                            link.active
                                ? 'border-neutral-950 bg-neutral-950 text-white dark:border-white dark:bg-white dark:text-neutral-950'
                                : 'border-neutral-300 dark:border-neutral-700'
                        }`}
                        dangerouslySetInnerHTML={{ __html: link.label }}
                    />
                ) : (
                    <span
                        key={i}
                        className="rounded-lg border border-neutral-200 px-3 py-1.5 text-sm text-neutral-400 dark:border-neutral-800"
                        dangerouslySetInnerHTML={{ __html: link.label }}
                    />
                )
            )}
        </div>
    );
}

export default function ClientsIndex({
    owner,
    walletSummary,
    clients,
    filters = {},
    activationFee,
}) {
    const create = useForm({
        name: '',
        email: '',
        phone: '',
        address: '',
        initial_credit: '0',
        admin_name: '',
        admin_email: '',
        admin_password: '',
    });

    const submit = (e) => {
        e.preventDefault();
        create.post(route('white-label.admin.clients.store'), {
            preserveScroll: true,
            onSuccess: () => create.reset(),
        });
    };

    const search = (e) => {
        e.preventDefault();
        const q = e.currentTarget.elements.search.value;
        router.get(
            route('white-label.admin.clients.index'),
            { search: q },
            { preserveState: true, replace: true }
        );
    };

    return (
        <WhiteLabelAdminLayout
            title="Clients"
            owner={owner}
            walletSummary={walletSummary}
        >
            <Head title="White-label Clients" />
            <FlashMessages />

            <div className="grid gap-6 xl:grid-cols-[380px_1fr]">
                <form onSubmit={submit} className={cardClass}>
                    <div className="mb-5 flex items-center gap-2">
                        <UserPlus className="h-5 w-5" />
                        <div>
                            <h2 className="font-semibold">Create Client</h2>
                            <p className="text-xs text-neutral-500">
                                Activation fee: {walletSummary?.currency_code} {activationFee}
                            </p>
                        </div>
                    </div>

                    <div className="space-y-3">
                        <input
                            className={fieldClass}
                            placeholder="Client name"
                            value={create.data.name}
                            onChange={(e) => create.setData('name', e.target.value)}
                            required
                        />
                        <input
                            className={fieldClass}
                            type="email"
                            placeholder="Client email"
                            value={create.data.email}
                            onChange={(e) => create.setData('email', e.target.value)}
                        />
                        <input
                            className={fieldClass}
                            placeholder="Phone"
                            value={create.data.phone}
                            onChange={(e) => create.setData('phone', e.target.value)}
                        />
                        <textarea
                            className={fieldClass}
                            placeholder="Address"
                            value={create.data.address}
                            onChange={(e) => create.setData('address', e.target.value)}
                        />
                        <input
                            className={fieldClass}
                            inputMode="decimal"
                            placeholder="Initial wallet credit"
                            value={create.data.initial_credit}
                            onChange={(e) => create.setData('initial_credit', e.target.value)}
                        />

                        <div className="border-t border-neutral-200 pt-4 dark:border-neutral-800">
                            <div className="mb-3 text-xs font-semibold uppercase tracking-wide text-neutral-500">
                                Optional first client administrator
                            </div>
                            <div className="space-y-3">
                                <input
                                    className={fieldClass}
                                    placeholder="Admin name"
                                    value={create.data.admin_name}
                                    onChange={(e) => create.setData('admin_name', e.target.value)}
                                />
                                <input
                                    className={fieldClass}
                                    type="email"
                                    placeholder="Admin email"
                                    value={create.data.admin_email}
                                    onChange={(e) => create.setData('admin_email', e.target.value)}
                                />
                                <input
                                    className={fieldClass}
                                    type="password"
                                    placeholder="Admin password (min 8)"
                                    value={create.data.admin_password}
                                    onChange={(e) => create.setData('admin_password', e.target.value)}
                                />
                            </div>
                        </div>

                        <button
                            disabled={create.processing}
                            className="w-full rounded-xl bg-neutral-950 px-4 py-2.5 text-sm font-semibold text-white disabled:opacity-50 dark:bg-white dark:text-neutral-950"
                        >
                            {create.processing ? 'Creating…' : 'Create Client'}
                        </button>
                    </div>
                </form>

                <div className={cardClass}>
                    <form onSubmit={search} className="mb-5 flex gap-2">
                        <div className="relative flex-1">
                            <Search className="absolute left-3 top-3 h-4 w-4 text-neutral-400" />
                            <input
                                name="search"
                                defaultValue={filters.search || ''}
                                className={`${fieldClass} pl-9`}
                                placeholder="Search clients"
                            />
                        </div>
                        <button className="rounded-xl border border-neutral-300 px-4 text-sm font-medium dark:border-neutral-700">
                            Search
                        </button>
                    </form>

                    <div className="overflow-x-auto">
                        <table className="w-full text-left text-sm">
                            <thead className="text-xs uppercase text-neutral-500">
                                <tr>
                                    <th className="pb-3">Client</th>
                                    <th className="pb-3">Owner</th>
                                    <th className="pb-3">Users</th>
                                    <th className="pb-3">Wallet</th>
                                    <th className="pb-3">Status</th>
                                    <th />
                                </tr>
                            </thead>
                            <tbody>
                                {(clients?.data || []).map((client) => (
                                    <tr
                                        key={client.id}
                                        className="border-t border-neutral-100 dark:border-neutral-800"
                                    >
                                        <td className="py-4 pr-4">
                                            <div className="font-medium">{client.name}</div>
                                            <div className="text-xs text-neutral-500">{client.email}</div>
                                        </td>
                                        <td className="py-4 pr-4">{client.reseller || owner?.name}</td>
                                        <td className="py-4 pr-4">{client.users_count}</td>
                                        <td className="py-4 pr-4">
                                            {walletSummary?.currency_code} {client.wallet_balance}
                                        </td>
                                        <td className="py-4 pr-4 capitalize">{client.status}</td>
                                        <td className="py-4 text-right">
                                            <Link
                                                href={route('white-label.admin.clients.show', client.id)}
                                                className="inline-flex items-center gap-1 font-medium"
                                            >
                                                Manage <ArrowRight className="h-4 w-4" />
                                            </Link>
                                        </td>
                                    </tr>
                                ))}
                                {!clients?.data?.length && (
                                    <tr>
                                        <td colSpan="6" className="py-10 text-center text-neutral-500">
                                            No clients found.
                                        </td>
                                    </tr>
                                )}
                            </tbody>
                        </table>
                    </div>

                    <Pagination links={clients?.links || []} />
                </div>
            </div>
        </WhiteLabelAdminLayout>
    );
}
JSX_3_WLADMIN

mkdir -p "$(dirname 'resources/js/Pages/WhiteLabel/Admin/Clients/Show.jsx')"
cat > 'resources/js/Pages/WhiteLabel/Admin/Clients/Show.jsx' <<'JSX_4_WLADMIN'
import { Head, Link, router, useForm } from '@inertiajs/react';
import { ArrowLeft, WalletCards, UserPlus, Trash2 } from 'lucide-react';
import WhiteLabelAdminLayout, {
    FlashMessages,
    cardClass,
    fieldClass,
} from '@/Layouts/WhiteLabelAdminLayout';

function UserRow({ clientId, user }) {
    const form = useForm({
        name: user.name || '',
        email: user.email || '',
        client_role: user.client_role || 'staff',
        status: user.status || 'active',
        password: '',
    });

    const save = (e) => {
        e.preventDefault();
        form.put(
            route('white-label.admin.clients.users.update', {
                client: clientId,
                user: user.id,
            }),
            { preserveScroll: true }
        );
    };

    return (
        <form
            onSubmit={save}
            className="grid gap-2 rounded-xl border border-neutral-200 p-3 dark:border-neutral-800 md:grid-cols-6"
        >
            <input className={fieldClass} value={form.data.name} onChange={(e) => form.setData('name', e.target.value)} />
            <input className={fieldClass} type="email" value={form.data.email} onChange={(e) => form.setData('email', e.target.value)} />
            <select className={fieldClass} value={form.data.client_role} onChange={(e) => form.setData('client_role', e.target.value)}>
                <option value="administrator">Administrator</option>
                <option value="staff">Staff</option>
            </select>
            <select className={fieldClass} value={form.data.status} onChange={(e) => form.setData('status', e.target.value)}>
                <option value="active">Active</option>
                <option value="inactive">Inactive</option>
            </select>
            <input className={fieldClass} type="password" placeholder="New password" value={form.data.password} onChange={(e) => form.setData('password', e.target.value)} />
            <div className="flex gap-2">
                <button className="flex-1 rounded-xl bg-neutral-950 px-3 py-2 text-xs font-semibold text-white dark:bg-white dark:text-neutral-950">
                    Save
                </button>
                <button
                    type="button"
                    onClick={() => {
                        if (confirm('Remove this user?')) {
                            router.delete(
                                route('white-label.admin.clients.users.destroy', {
                                    client: clientId,
                                    user: user.id,
                                }),
                                { preserveScroll: true }
                            );
                        }
                    }}
                    className="rounded-xl border border-red-200 px-3 py-2 text-red-600 dark:border-red-900"
                >
                    <Trash2 className="h-4 w-4" />
                </button>
            </div>
        </form>
    );
}

export default function ClientShow({ owner, walletSummary, client }) {
    const edit = useForm({
        name: client.name || '',
        email: client.email || '',
        phone: client.phone || '',
        address: client.address || '',
        status: client.status || 'active',
    });

    const addUser = useForm({
        name: '',
        email: '',
        password: '',
        client_role: 'administrator',
    });

    const fund = useForm({ amount: '' });
    const reclaim = useForm({ amount: '' });

    return (
        <WhiteLabelAdminLayout
            title={`Client · ${client.name}`}
            owner={owner}
            walletSummary={walletSummary}
        >
            <Head title={`Manage ${client.name}`} />
            <FlashMessages />

            <Link
                href={route('white-label.admin.clients.index')}
                className="mb-5 inline-flex items-center gap-1 text-sm text-neutral-500"
            >
                <ArrowLeft className="h-4 w-4" /> Back to Clients
            </Link>

            <div className="grid gap-6 xl:grid-cols-3">
                <form
                    onSubmit={(e) => {
                        e.preventDefault();
                        edit.put(route('white-label.admin.clients.update', client.id), {
                            preserveScroll: true,
                        });
                    }}
                    className={`${cardClass} xl:col-span-2`}
                >
                    <h2 className="mb-4 font-semibold">Client Details</h2>
                    <div className="grid gap-3 md:grid-cols-2">
                        <input className={fieldClass} value={edit.data.name} onChange={(e) => edit.setData('name', e.target.value)} />
                        <input className={fieldClass} type="email" value={edit.data.email} onChange={(e) => edit.setData('email', e.target.value)} />
                        <input className={fieldClass} value={edit.data.phone} onChange={(e) => edit.setData('phone', e.target.value)} placeholder="Phone" />
                        <select className={fieldClass} value={edit.data.status} onChange={(e) => edit.setData('status', e.target.value)}>
                            <option value="active">Active</option>
                            <option value="inactive">Inactive</option>
                        </select>
                        <textarea className={`${fieldClass} md:col-span-2`} value={edit.data.address} onChange={(e) => edit.setData('address', e.target.value)} placeholder="Address" />
                    </div>
                    <button className="mt-4 rounded-xl bg-neutral-950 px-4 py-2.5 text-sm font-semibold text-white dark:bg-white dark:text-neutral-950">
                        Save Client
                    </button>
                </form>

                <div className={cardClass}>
                    <div className="mb-4 flex items-center gap-2">
                        <WalletCards className="h-5 w-5" />
                        <h2 className="font-semibold">Client Wallet</h2>
                    </div>
                    <div className="mb-4 text-2xl font-semibold">
                        {walletSummary?.currency_code} {client.wallet_balance}
                    </div>

                    <form
                        className="mb-3 flex gap-2"
                        onSubmit={(e) => {
                            e.preventDefault();
                            fund.post(route('white-label.admin.clients.fund', client.id), {
                                preserveScroll: true,
                                onSuccess: () => fund.reset(),
                            });
                        }}
                    >
                        <input className={fieldClass} placeholder="Amount" value={fund.data.amount} onChange={(e) => fund.setData('amount', e.target.value)} />
                        <button className="rounded-xl bg-neutral-950 px-3 text-xs font-semibold text-white dark:bg-white dark:text-neutral-950">
                            Fund
                        </button>
                    </form>

                    <form
                        className="flex gap-2"
                        onSubmit={(e) => {
                            e.preventDefault();
                            reclaim.post(route('white-label.admin.clients.reclaim', client.id), {
                                preserveScroll: true,
                                onSuccess: () => reclaim.reset(),
                            });
                        }}
                    >
                        <input className={fieldClass} placeholder="Amount" value={reclaim.data.amount} onChange={(e) => reclaim.setData('amount', e.target.value)} />
                        <button className="rounded-xl border border-neutral-300 px-3 text-xs font-semibold dark:border-neutral-700">
                            Reclaim
                        </button>
                    </form>
                </div>
            </div>

            <div className={`${cardClass} mt-6`}>
                <div className="mb-4 flex items-center gap-2">
                    <UserPlus className="h-5 w-5" />
                    <h2 className="font-semibold">Client Users</h2>
                </div>

                <form
                    className="mb-5 grid gap-3 md:grid-cols-4"
                    onSubmit={(e) => {
                        e.preventDefault();
                        addUser.post(
                            route('white-label.admin.clients.users.store', client.id),
                            {
                                preserveScroll: true,
                                onSuccess: () => addUser.reset(),
                            }
                        );
                    }}
                >
                    <input className={fieldClass} placeholder="Name" value={addUser.data.name} onChange={(e) => addUser.setData('name', e.target.value)} />
                    <input className={fieldClass} type="email" placeholder="Email" value={addUser.data.email} onChange={(e) => addUser.setData('email', e.target.value)} />
                    <input className={fieldClass} type="password" placeholder="Password" value={addUser.data.password} onChange={(e) => addUser.setData('password', e.target.value)} />
                    <div className="flex gap-2">
                        <select className={fieldClass} value={addUser.data.client_role} onChange={(e) => addUser.setData('client_role', e.target.value)}>
                            <option value="administrator">Administrator</option>
                            <option value="staff">Staff</option>
                        </select>
                        <button className="rounded-xl bg-neutral-950 px-4 text-sm font-semibold text-white dark:bg-white dark:text-neutral-950">
                            Add
                        </button>
                    </div>
                </form>

                <div className="space-y-3">
                    {(client.users || []).map((user) => (
                        <UserRow key={user.id} clientId={client.id} user={user} />
                    ))}
                    {!client.users?.length && (
                        <div className="py-6 text-center text-sm text-neutral-500">
                            No users yet.
                        </div>
                    )}
                </div>
            </div>
        </WhiteLabelAdminLayout>
    );
}
JSX_4_WLADMIN

mkdir -p "$(dirname 'resources/js/Pages/WhiteLabel/Admin/Resellers/Index.jsx')"
cat > 'resources/js/Pages/WhiteLabel/Admin/Resellers/Index.jsx' <<'JSX_5_WLADMIN'
import { Head, useForm } from '@inertiajs/react';
import { Building2, WalletCards, UserPlus } from 'lucide-react';
import WhiteLabelAdminLayout, {
    FlashMessages,
    cardClass,
    fieldClass,
} from '@/Layouts/WhiteLabelAdminLayout';

function ResellerCard({ reseller, owner, walletSummary }) {
    const edit = useForm({
        name: reseller.name || '',
        email: reseller.email || '',
        phone: reseller.phone || '',
        status: reseller.status || 'active',
    });
    const fund = useForm({ amount: '' });
    const reclaim = useForm({ amount: '' });
    const addUser = useForm({ name: '', email: '', password: '' });

    return (
        <div className={cardClass}>
            <div className="mb-4 flex items-start justify-between gap-4">
                <div>
                    <h3 className="font-semibold">{reseller.name}</h3>
                    <p className="text-xs text-neutral-500">
                        {reseller.clients_count} clients · {reseller.users?.length || 0} admins
                    </p>
                </div>
                <div className="rounded-xl bg-neutral-100 px-3 py-2 text-sm font-semibold dark:bg-neutral-800">
                    {walletSummary?.currency_code} {reseller.wallet_balance}
                </div>
            </div>

            <form
                className="grid gap-2 md:grid-cols-4"
                onSubmit={(e) => {
                    e.preventDefault();
                    edit.put(route('white-label.admin.resellers.update', reseller.id), {
                        preserveScroll: true,
                    });
                }}
            >
                <input className={fieldClass} value={edit.data.name} onChange={(e) => edit.setData('name', e.target.value)} />
                <input className={fieldClass} type="email" value={edit.data.email} onChange={(e) => edit.setData('email', e.target.value)} />
                <input className={fieldClass} value={edit.data.phone} onChange={(e) => edit.setData('phone', e.target.value)} placeholder="Phone" />
                <div className="flex gap-2">
                    <select className={fieldClass} value={edit.data.status} onChange={(e) => edit.setData('status', e.target.value)}>
                        <option value="active">Active</option>
                        <option value="inactive">Inactive</option>
                    </select>
                    <button className="rounded-xl bg-neutral-950 px-4 text-xs font-semibold text-white dark:bg-white dark:text-neutral-950">
                        Save
                    </button>
                </div>
            </form>

            <div className="mt-4 grid gap-3 border-t border-neutral-200 pt-4 dark:border-neutral-800 lg:grid-cols-3">
                <form
                    className="flex gap-2"
                    onSubmit={(e) => {
                        e.preventDefault();
                        fund.post(route('white-label.admin.resellers.fund', reseller.id), {
                            preserveScroll: true,
                            onSuccess: () => fund.reset(),
                        });
                    }}
                >
                    <input className={fieldClass} placeholder="Fund amount" value={fund.data.amount} onChange={(e) => fund.setData('amount', e.target.value)} />
                    <button className="rounded-xl bg-neutral-950 px-3 text-xs font-semibold text-white dark:bg-white dark:text-neutral-950">
                        Fund
                    </button>
                </form>

                <form
                    className="flex gap-2"
                    onSubmit={(e) => {
                        e.preventDefault();
                        reclaim.post(route('white-label.admin.resellers.reclaim', reseller.id), {
                            preserveScroll: true,
                            onSuccess: () => reclaim.reset(),
                        });
                    }}
                >
                    <input className={fieldClass} placeholder="Reclaim amount" value={reclaim.data.amount} onChange={(e) => reclaim.setData('amount', e.target.value)} />
                    <button className="rounded-xl border border-neutral-300 px-3 text-xs font-semibold dark:border-neutral-700">
                        Reclaim
                    </button>
                </form>

                <form
                    className="grid grid-cols-3 gap-2"
                    onSubmit={(e) => {
                        e.preventDefault();
                        addUser.post(
                            route('white-label.admin.resellers.users.store', reseller.id),
                            {
                                preserveScroll: true,
                                onSuccess: () => addUser.reset(),
                            }
                        );
                    }}
                >
                    <input className={fieldClass} placeholder="Admin name" value={addUser.data.name} onChange={(e) => addUser.setData('name', e.target.value)} />
                    <input className={fieldClass} type="email" placeholder="Admin email" value={addUser.data.email} onChange={(e) => addUser.setData('email', e.target.value)} />
                    <div className="flex gap-2">
                        <input className={fieldClass} type="password" placeholder="Password" value={addUser.data.password} onChange={(e) => addUser.setData('password', e.target.value)} />
                        <button className="rounded-xl border border-neutral-300 px-3 dark:border-neutral-700">
                            <UserPlus className="h-4 w-4" />
                        </button>
                    </div>
                </form>
            </div>
        </div>
    );
}

export default function ResellersIndex({
    owner,
    walletSummary,
    resellers = [],
    activationFee,
}) {
    const create = useForm({
        name: '',
        email: '',
        phone: '',
        admin_name: '',
        admin_email: '',
        password: '',
        initial_credit: '0',
    });

    return (
        <WhiteLabelAdminLayout
            title="Resellers"
            owner={owner}
            walletSummary={walletSummary}
        >
            <Head title="White-label Resellers" />
            <FlashMessages />

            <div className="mb-6 rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-900 dark:border-amber-900 dark:bg-amber-950/30 dark:text-amber-200">
                This panel can create ordinary resellers only. Creating another
                white-label owner/panel is blocked in the backend.
            </div>

            <div className="grid gap-6 xl:grid-cols-[380px_1fr]">
                <form
                    className={cardClass}
                    onSubmit={(e) => {
                        e.preventDefault();
                        create.post(route('white-label.admin.resellers.store'), {
                            preserveScroll: true,
                            onSuccess: () => create.reset(),
                        });
                    }}
                >
                    <div className="mb-5 flex items-center gap-2">
                        <Building2 className="h-5 w-5" />
                        <div>
                            <h2 className="font-semibold">Create Reseller</h2>
                            <p className="text-xs text-neutral-500">
                                Activation fee: {walletSummary?.currency_code} {activationFee}
                            </p>
                        </div>
                    </div>

                    <div className="space-y-3">
                        <input className={fieldClass} placeholder="Reseller name" value={create.data.name} onChange={(e) => create.setData('name', e.target.value)} />
                        <input className={fieldClass} type="email" placeholder="Business email" value={create.data.email} onChange={(e) => create.setData('email', e.target.value)} />
                        <input className={fieldClass} placeholder="Phone" value={create.data.phone} onChange={(e) => create.setData('phone', e.target.value)} />
                        <input className={fieldClass} placeholder="Administrator name" value={create.data.admin_name} onChange={(e) => create.setData('admin_name', e.target.value)} />
                        <input className={fieldClass} type="email" placeholder="Login email" value={create.data.admin_email} onChange={(e) => create.setData('admin_email', e.target.value)} />
                        <input className={fieldClass} type="password" placeholder="Password (min 8)" value={create.data.password} onChange={(e) => create.setData('password', e.target.value)} />
                        <input className={fieldClass} placeholder="Initial reseller credit" value={create.data.initial_credit} onChange={(e) => create.setData('initial_credit', e.target.value)} />

                        <button
                            disabled={create.processing}
                            className="w-full rounded-xl bg-neutral-950 px-4 py-2.5 text-sm font-semibold text-white disabled:opacity-50 dark:bg-white dark:text-neutral-950"
                        >
                            {create.processing ? 'Creating…' : 'Create Reseller'}
                        </button>
                    </div>
                </form>

                <div className="space-y-4">
                    {resellers.map((reseller) => (
                        <ResellerCard
                            key={reseller.id}
                            reseller={reseller}
                            owner={owner}
                            walletSummary={walletSummary}
                        />
                    ))}
                    {!resellers.length && (
                        <div className={`${cardClass} py-12 text-center text-neutral-500`}>
                            No resellers created yet.
                        </div>
                    )}
                </div>
            </div>
        </WhiteLabelAdminLayout>
    );
}
JSX_5_WLADMIN

mkdir -p "$(dirname 'resources/js/Pages/WhiteLabel/Admin/Wallet.jsx')"
cat > 'resources/js/Pages/WhiteLabel/Admin/Wallet.jsx' <<'JSX_6_WLADMIN'
import { Head } from '@inertiajs/react';
import { WalletCards } from 'lucide-react';
import WhiteLabelAdminLayout, {
    FlashMessages,
    cardClass,
} from '@/Layouts/WhiteLabelAdminLayout';

export default function Wallet({ owner, walletSummary, transactions = [] }) {
    return (
        <WhiteLabelAdminLayout
            title="Wallet"
            owner={owner}
            walletSummary={walletSummary}
        >
            <Head title="White-label Wallet" />
            <FlashMessages />

            <div className="grid gap-6 xl:grid-cols-[320px_1fr]">
                <div className={cardClass}>
                    <div className="flex items-center gap-2">
                        <WalletCards className="h-5 w-5" />
                        <h2 className="font-semibold">Master Wallet</h2>
                    </div>
                    <div className="mt-5 text-3xl font-semibold">
                        {walletSummary?.currency_code} {walletSummary?.balance}
                    </div>
                    <div className="mt-2 text-sm capitalize text-neutral-500">
                        Status: {walletSummary?.status}
                    </div>
                    <p className="mt-5 text-xs leading-5 text-neutral-500">
                        Only the platform administrator can add new master credit.
                        This white-label panel can distribute existing credit to its
                        clients/resellers and reclaim unused credit.
                    </p>
                </div>

                <div className={cardClass}>
                    <h2 className="mb-4 font-semibold">Wallet Ledger</h2>
                    <div className="overflow-x-auto">
                        <table className="w-full text-left text-sm">
                            <thead className="text-xs uppercase text-neutral-500">
                                <tr>
                                    <th className="pb-3">Date</th>
                                    <th className="pb-3">Type</th>
                                    <th className="pb-3">Direction</th>
                                    <th className="pb-3 text-right">Amount</th>
                                    <th className="pb-3 text-right">Balance</th>
                                </tr>
                            </thead>
                            <tbody>
                                {transactions.map((tx) => (
                                    <tr key={tx.id} className="border-t border-neutral-100 dark:border-neutral-800">
                                        <td className="py-3 pr-4 text-xs text-neutral-500">
                                            {tx.created_at ? new Date(tx.created_at).toLocaleString() : '—'}
                                        </td>
                                        <td className="py-3 pr-4">
                                            <div className="font-medium">{tx.type}</div>
                                            <div className="text-xs text-neutral-500">{tx.description}</div>
                                        </td>
                                        <td className="py-3 pr-4 capitalize">{tx.direction}</td>
                                        <td className="py-3 pr-4 text-right">
                                            {walletSummary?.currency_code} {tx.amount}
                                        </td>
                                        <td className="py-3 text-right font-medium">
                                            {walletSummary?.currency_code} {tx.balance_after}
                                        </td>
                                    </tr>
                                ))}
                                {!transactions.length && (
                                    <tr>
                                        <td colSpan="5" className="py-10 text-center text-neutral-500">
                                            No transactions yet.
                                        </td>
                                    </tr>
                                )}
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </WhiteLabelAdminLayout>
    );
}
JSX_6_WLADMIN

mkdir -p "$(dirname 'resources/js/Pages/WhiteLabel/Admin/Settings.jsx')"
cat > 'resources/js/Pages/WhiteLabel/Admin/Settings.jsx' <<'JSX_7_WLADMIN'
import { Head, useForm } from '@inertiajs/react';
import { Palette, UserPlus } from 'lucide-react';
import WhiteLabelAdminLayout, {
    FlashMessages,
    cardClass,
    fieldClass,
} from '@/Layouts/WhiteLabelAdminLayout';

function TeamUser({ user }) {
    const form = useForm({
        name: user.name || '',
        email: user.email || '',
        status: user.status || 'active',
        password: '',
    });

    return (
        <form
            className="grid gap-2 rounded-xl border border-neutral-200 p-3 dark:border-neutral-800 md:grid-cols-5"
            onSubmit={(e) => {
                e.preventDefault();
                form.put(route('white-label.admin.settings.team.update', user.id), {
                    preserveScroll: true,
                });
            }}
        >
            <input className={fieldClass} value={form.data.name} onChange={(e) => form.setData('name', e.target.value)} />
            <input className={fieldClass} type="email" value={form.data.email} onChange={(e) => form.setData('email', e.target.value)} />
            <select className={fieldClass} value={form.data.status} onChange={(e) => form.setData('status', e.target.value)}>
                <option value="active">Active</option>
                <option value="inactive">Inactive</option>
            </select>
            <input className={fieldClass} type="password" placeholder="New password" value={form.data.password} onChange={(e) => form.setData('password', e.target.value)} />
            <button className="rounded-xl bg-neutral-950 px-4 py-2 text-sm font-semibold text-white dark:bg-white dark:text-neutral-950">
                Save
            </button>
        </form>
    );
}

export default function Settings({
    owner,
    walletSummary,
    brandingSettings = {},
    teamUsers = [],
}) {
    const branding = useForm({
        brand_name: brandingSettings.brand_name || '',
        primary_color: brandingSettings.primary_color || '#467235',
        tagline: brandingSettings.tagline || '',
        support_email: brandingSettings.support_email || '',
        support_phone: brandingSettings.support_phone || '',
        login_heading: brandingSettings.login_heading || '',
    });

    const team = useForm({
        name: '',
        email: '',
        password: '',
    });

    return (
        <WhiteLabelAdminLayout
            title="Branding & Team"
            owner={owner}
            walletSummary={walletSummary}
        >
            <Head title="White-label Settings" />
            <FlashMessages />

            <div className="grid gap-6 xl:grid-cols-2">
                <form
                    className={cardClass}
                    onSubmit={(e) => {
                        e.preventDefault();
                        branding.put(route('white-label.admin.settings.branding.update'), {
                            preserveScroll: true,
                        });
                    }}
                >
                    <div className="mb-5 flex items-center gap-2">
                        <Palette className="h-5 w-5" />
                        <h2 className="font-semibold">Portal Branding</h2>
                    </div>
                    <div className="space-y-3">
                        <input className={fieldClass} placeholder="Brand name" value={branding.data.brand_name} onChange={(e) => branding.setData('brand_name', e.target.value)} />
                        <input className={fieldClass} placeholder="Login heading" value={branding.data.login_heading} onChange={(e) => branding.setData('login_heading', e.target.value)} />
                        <input className={fieldClass} placeholder="Tagline" value={branding.data.tagline} onChange={(e) => branding.setData('tagline', e.target.value)} />
                        <input className={fieldClass} type="email" placeholder="Support email" value={branding.data.support_email} onChange={(e) => branding.setData('support_email', e.target.value)} />
                        <input className={fieldClass} placeholder="Support phone" value={branding.data.support_phone} onChange={(e) => branding.setData('support_phone', e.target.value)} />
                        <label className="block text-xs text-neutral-500">
                            Primary color
                            <input className={`${fieldClass} mt-1`} type="color" value={branding.data.primary_color} onChange={(e) => branding.setData('primary_color', e.target.value)} />
                        </label>
                        <button className="w-full rounded-xl bg-neutral-950 px-4 py-2.5 text-sm font-semibold text-white dark:bg-white dark:text-neutral-950">
                            Save Branding
                        </button>
                    </div>
                </form>

                <div className={cardClass}>
                    <div className="mb-5 flex items-center gap-2">
                        <UserPlus className="h-5 w-5" />
                        <h2 className="font-semibold">Add White-label Administrator</h2>
                    </div>
                    <form
                        className="space-y-3"
                        onSubmit={(e) => {
                            e.preventDefault();
                            team.post(route('white-label.admin.settings.team.store'), {
                                preserveScroll: true,
                                onSuccess: () => team.reset(),
                            });
                        }}
                    >
                        <input className={fieldClass} placeholder="Name" value={team.data.name} onChange={(e) => team.setData('name', e.target.value)} />
                        <input className={fieldClass} type="email" placeholder="Email" value={team.data.email} onChange={(e) => team.setData('email', e.target.value)} />
                        <input className={fieldClass} type="password" placeholder="Password (min 8)" value={team.data.password} onChange={(e) => team.setData('password', e.target.value)} />
                        <button className="w-full rounded-xl border border-neutral-300 px-4 py-2.5 text-sm font-semibold dark:border-neutral-700">
                            Add Administrator
                        </button>
                    </form>
                </div>
            </div>

            <div className={`${cardClass} mt-6`}>
                <h2 className="mb-4 font-semibold">Administrator Accounts</h2>
                <div className="space-y-3">
                    {teamUsers.map((user) => (
                        <TeamUser key={user.id} user={user} />
                    ))}
                </div>
            </div>
        </WhiteLabelAdminLayout>
    );
}
JSX_7_WLADMIN


echo
echo "===== FRONTEND BUILD BEFORE ROUTE SWITCH ====="
npm run build

echo
echo "===== PATCH ROUTE LOADER + LOGIN REDIRECT ====="
python3 <<'PY'
from pathlib import Path

# Load the white-label admin route file immediately after auth routes.
p = Path("routes/web.php")
s = p.read_text()

include = "require __DIR__.'/white_label_admin.php';"

if include not in s:
    anchor = "require __DIR__.'/auth.php';"
    if anchor not in s:
        raise SystemExit("STOP: routes/web.php auth include anchor not found.")
    s = s.replace(anchor, anchor + "\n\n" + include, 1)
    p.write_text(s)
    print("routes/web.php: white-label admin routes enabled")
else:
    print("routes/web.php: route loader already installed")

# White-label owner should land on the admin-style tenant dashboard after login.
p = Path("app/Http/Controllers/Reseller/AuthController.php")
s = p.read_text()

if "white-label.admin.dashboard" not in s:
    create_patterns = [
        """return redirect()->route('reseller.dashboard');""",
        """return redirect()->route(
                'reseller.dashboard'
            );""",
    ]

    create_replacement = """if (
                    ! $reseller->parent_reseller_id
                    && (bool) ($reseller->white_label_enabled ?? false)
                ) {
                    return redirect()->route('white-label.admin.dashboard');
                }

                return redirect()->route('reseller.dashboard');"""

    replaced_create = False
    for old in create_patterns:
        if old in s:
            s = s.replace(old, create_replacement, 1)
            replaced_create = True
            break

    store_patterns = [
        """return redirect()->intended(route('reseller.dashboard'));""",
        """return redirect()->intended(
            route('reseller.dashboard')
        );""",
    ]

    store_replacement = """if (
            ! $reseller->parent_reseller_id
            && (bool) ($reseller->white_label_enabled ?? false)
        ) {
            return redirect()->route('white-label.admin.dashboard');
        }

        return redirect()->intended(route('reseller.dashboard'));"""

    replaced_store = False
    for old in store_patterns:
        if old in s:
            s = s.replace(old, store_replacement, 1)
            replaced_store = True
            break

    if not replaced_create or not replaced_store:
        raise SystemExit(
            "STOP: reseller login redirect anchors changed. "
            "Nothing will be guessed; restore happened automatically."
        )

    p.write_text(s)
    print("AuthController.php: white-label owner login redirect installed")
else:
    print("AuthController.php: white-label redirect already installed")
PY

echo
echo "===== PHP SYNTAX ====="
php -l app/Http/Middleware/EnsureWhiteLabelAdmin.php
php -l app/Http/Controllers/WhiteLabel/Admin/TenantController.php
php -l app/Http/Controllers/WhiteLabel/Admin/DashboardController.php
php -l app/Http/Controllers/WhiteLabel/Admin/ClientController.php
php -l app/Http/Controllers/WhiteLabel/Admin/ResellerController.php
php -l app/Http/Controllers/WhiteLabel/Admin/WalletController.php
php -l app/Http/Controllers/WhiteLabel/Admin/SettingsController.php
php -l routes/white_label_admin.php
php -l routes/web.php
php -l app/Http/Controllers/Reseller/AuthController.php

echo
echo "===== OWNERSHIP ====="
for f in "${TARGETS[@]}"; do
    [ -e "$f" ] && chown "$APP_USER:$APP_GROUP" "$f"
done
[ -d public/build ] && chown -R "$APP_USER:$APP_GROUP" public/build

echo
echo "===== LARAVEL REFRESH ====="
COMPOSER_ALLOW_SUPERUSER=1 composer dump-autoload -o
php artisan optimize:clear
php artisan config:cache
php artisan queue:restart || true

echo
echo "===== ROUTE VERIFY ====="
php artisan route:list | grep -E \
'reseller/admin|white-label\.admin|reseller/login' \
| head -120

echo
echo "===== SECURITY VERIFY ====="
php artisan tinker --execute='
use App\Models\Reseller;
use App\Models\Wallet;
$owners = Reseller::query()
    ->whereNull("parent_reseller_id")
    ->where("white_label_enabled", true)
    ->with("wallet")
    ->get()
    ->map(fn($r) => [
        "id" => $r->id,
        "name" => $r->name,
        "white_label_enabled" => (bool) $r->white_label_enabled,
        "wallet_balance_micros" => (int) ($r->wallet?->balance_micros ?? 0),
    ]);
dump($owners);
'

trap - ERR

echo
echo "============================================================"
echo " WHITE-LABEL ADMIN INSTALLED"
echo "============================================================"
echo "Login:"
echo "  https://YOUR-WHITE-LABEL-DOMAIN/reseller/login"
echo
echo "After login, a white-label owner is redirected to:"
echo "  /reseller/admin/dashboard"
echo
echo "Installed tenant-safe capabilities:"
echo "  - Admin-style dashboard"
echo "  - Create/manage tenant clients"
echo "  - Create/manage ordinary resellers"
echo "  - Nested white-label creation BLOCKED"
echo "  - Master wallet required for client/reseller creation"
echo "  - Activation fees debit master wallet when configured"
echo "  - Initial/future credit allocation and reclaim"
echo "  - Client users"
echo "  - Reseller administrators"
echo "  - White-label administrator team"
echo "  - Branding settings"
echo "  - Existing reseller rates linked"
echo
echo "Platform-only/global settings remain restricted to main admin."
echo "Backup: $BACKUP"
echo "============================================================"
