--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\config\config.php ---
<?php

return [
    'name' => 'AuthorizeNetGateway',
];


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\database\seeders\AuthorizeNetGatewayDatabaseSeeder.php ---
<?php

namespace Modules\AuthorizeNetGateway\Database\Seeders;

use Illuminate\Database\Seeder;

class AuthorizeNetGatewayDatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        // $this->call([]);
    }
}


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\Http\Controllers\Admin\AuthorizeNetConfigController.php ---
<?php

namespace Modules\AuthorizeNetGateway\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Setting; // Assuming your Setting model is in App\Models
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class AuthorizeNetConfigController extends Controller
{
    /**
     * Show the form for editing the Authorize.Net settings.
     *
     * @return \Illuminate\View\View
     */
    public function edit()
    {
        // Keys for Authorize.Net settings
        $settingKeys = [
            'authorizenet_enabled',
            'authorizenet_mode',
            'authorizenet_login_id',
            'authorizenet_transaction_key',
            'authorizenet_signature_key',
            'authorizenet_public_client_key',
        ];

        $settings = [];
        foreach ($settingKeys as $key) {
            $settings[$key] = Setting::getValue($key);
        }

        // Default 'authorizenet_enabled' to '0' if null (not yet saved)
        if (is_null($settings['authorizenet_enabled'])) {
            $settings['authorizenet_enabled'] = '0';
        }
        // Default 'authorizenet_mode' to 'sandbox' if null
        if (is_null($settings['authorizenet_mode'])) {
            $settings['authorizenet_mode'] = 'sandbox';
        }

        return view('authorizenetgateway::admin.config', compact('settings'));
    }

    /**
     * Update the Authorize.Net settings in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(Request $request)
    {
        $request->validate([
            'authorizenet_enabled' => 'nullable|boolean', // Checkbox might not be present if unchecked
            'authorizenet_mode' => 'required|in:sandbox,live',
            'authorizenet_login_id' => 'nullable|string|max:255',
            'authorizenet_transaction_key' => 'nullable|string|max:255',
            'authorizenet_signature_key' => 'nullable|string|max:255',
            'authorizenet_public_client_key' => 'nullable|string|max:255',
        ]);

        try {
            Setting::setValue('authorizenet_enabled', $request->input('authorizenet_enabled', '0'), 'Enable Authorize.Net Gateway', 'Payment Gateways', 'boolean');
            Setting::setValue('authorizenet_mode', $request->input('authorizenet_mode', 'sandbox'), 'Authorize.Net Mode', 'Payment Gateways', 'select');
            Setting::setValue('authorizenet_login_id', $request->input('authorizenet_login_id'), 'Authorize.Net API Login ID', 'Payment Gateways', 'text');
            Setting::setValue('authorizenet_transaction_key', $request->input('authorizenet_transaction_key'), 'Authorize.Net Transaction Key', 'Payment Gateways', 'password');
            Setting::setValue('authorizenet_signature_key', $request->input('authorizenet_signature_key'), 'Authorize.Net Signature Key (Webhooks)', 'Payment Gateways', 'password');
            Setting::setValue('authorizenet_public_client_key', $request->input('authorizenet_public_client_key'), 'Authorize.Net Public Client Key', 'Payment Gateways', 'text');

            return redirect()->route('admin.authorizenetgateway.settings.edit')->with('success', 'Authorize.Net settings updated successfully.');
        } catch (\Exception $e) {
            Log::error('Error updating Authorize.Net settings: ' . $e->getMessage());
            return redirect()->route('admin.authorizenetgateway.settings.edit')->with('error', 'Failed to update Authorize.Net settings. Please try again.');
        }
    }
}


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\Http\Controllers\AuthorizeNetGatewayController.php ---
<?php

namespace Modules\AuthorizeNetGateway\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class AuthorizeNetGatewayController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        return view('authorizenetgateway::index');
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        return view('authorizenetgateway::create');
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request) {}

    /**
     * Show the specified resource.
     */
    public function show($id)
    {
        return view('authorizenetgateway::show');
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit($id)
    {
        return view('authorizenetgateway::edit');
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, $id) {}

    /**
     * Remove the specified resource from storage.
     */
    public function destroy($id) {}
}


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\Http\Controllers\AuthorizeNetSubscriptionController.php ---
<?php

namespace Modules\AuthorizeNetGateway\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Subscription;
use App\Models\SubscriptionPlan;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Modules\AuthorizeNetGateway\Services\AuthorizeNetService;
use App\Services\CreditService;
use App\Services\WalletService;
use Spatie\Permission\Models\Role;

class AuthorizeNetSubscriptionController extends Controller
{
    protected AuthorizeNetService $authorizeNetService;
    protected CreditService $creditService;
    protected WalletService $walletService;

    public function __construct(
        AuthorizeNetService $authorizeNetService,
        CreditService $creditService,
        WalletService $walletService
    ) {
        $this->authorizeNetService = $authorizeNetService;
        $this->creditService = $creditService;
        $this->walletService = $walletService;
    }

    public function showCheckoutForm(Request $request, SubscriptionPlan $subscriptionPlan)
    {
        if (setting('authorizenet_enabled', '0') != '1') {
            return redirect()->route('subscription.plans')->with('error', 'Authorize.Net payments are currently disabled.');
        }

        $apiLoginId = setting('authorizenet_login_id');
        $publicClientKey = setting('authorizenet_public_client_key');
        
        if (!$apiLoginId || !$publicClientKey) {
            Log::error("Authorize.Net checkout form: API Login ID or Public Client Key is not set.");
            return redirect()->route('subscription.plans')->with('error', 'Authorize.Net gateway is not configured correctly.');
        }

        return view('authorizenetgateway::subscriptions.checkout', ['plan' => $subscriptionPlan, 'apiLoginId' => $apiLoginId, 'publicClientKey' => $publicClientKey]);
    }

    public function processSubscriptionWithAcceptJs(Request $request, SubscriptionPlan $plan)
    {
        if (setting('authorizenet_enabled', '0') != '1') {
            return redirect()->route('subscription.plans')->with('error', 'Authorize.Net payments are currently disabled.');
        }

        $request->validate([
            'authorizenet_data_descriptor' => 'required|string',
            'authorizenet_data_value' => 'required|string', // Payment nonce
        ]);

        /** @var User $user */
        $user = Auth::user();

        try {
            $opaqueData = [
                'dataDescriptor' => $request->input('authorizenet_data_descriptor'),
                'dataValue' => $request->input('authorizenet_data_value'),
            ];
            $customerDetails = ['email' => $user->email, 'firstName' => $user->name]; // Or more detailed if available
            $invoiceNumber = 'SUB-' . Str::random(6) . '-' . $user->id;
            $description = "Subscription to {$plan->name}";

            $response = $this->authorizeNetService->chargeCreditCard($plan->price, $opaqueData, $customerDetails, $invoiceNumber, $description);

            if ($response != null && $response->getMessages()->getResultCode() == "Ok" && $response->getTransactionResponse() != null && $response->getTransactionResponse()->getMessages() != null) {
                $transactionId = $response->getTransactionResponse()->getTransId();

                // Deactivate other existing subscriptions for this user
                $user->subscriptions()
                    ->whereIn('status', ['active', 'trialing'])
                    ->update(['status' => 'cancelled', 'ends_at' => now(), 'cancelled_at' => now()]);

                // Create new local subscription record
                $subscription = Subscription::create([
                    'user_id' => $user->id,
                    'subscription_plan_id' => $plan->id,
                    'payment_gateway' => 'authorizenetgateway',
                    'gateway_transaction_id' => $transactionId,
                    'status' => $plan->trial_period_days > 0 ? 'trialing' : 'active',
                    'price_at_purchase' => $plan->price,
                    'currency_at_purchase' => $plan->currency,
                    'trial_ends_at' => $plan->trial_period_days > 0 ? now()->addDays($plan->trial_period_days) : null,
                    'starts_at' => now(),
                    'ends_at' => now()->add($plan->interval, $plan->interval_count),
                ]);

                // Award credits
                if (function_exists('setting') && setting('credits_system_enabled', '0') == '1' && $plan->credits_awarded_on_purchase > 0) {
                    $this->creditService->awardCredits($user, $plan->credits_awarded_on_purchase, 'award_subscription_purchase', "Credits for {$plan->name} subscription", $subscription);
                }

                // Assign target role
                if (!empty($plan->target_role) && class_exists(Role::class) && Role::where('name', $plan->target_role)->where('guard_name', 'web')->exists()) {
                    $user->syncRoles([$plan->target_role]);
                }

                return redirect()->route('dashboard')->with('success', "Successfully subscribed to {$plan->name} via Authorize.Net!");
            }
            $errorMessage = $this->authorizeNetService->getErrorMessage($response);
            Log::error("Authorize.Net Subscription Error for user {$user->id}, plan {$plan->id}: " . $errorMessage, ['response' => $response]);
            return redirect()->route('subscription.authorizenet.checkout', ['subscriptionPlan' => $plan->slug])->with('error', 'Authorize.Net payment failed: ' . $errorMessage)->withInput();
        } catch (\Exception $e) {
            Log::error("Authorize.Net Subscription Exception for user {$user->id}, plan {$plan->id}: " . $e->getMessage());
            return redirect()->route('subscription.authorizenet.checkout', ['subscriptionPlan' => $plan->slug])->with('error', 'An error occurred while processing your payment with Authorize.Net.')->withInput();
        }
    }

    // --- Wallet Deposit Methods ---

    public function showWalletDepositForm(Request $request)
    {
        if (setting('authorizenet_enabled', '0') != '1' || setting('allow_wallet_deposits', '0') != '1') {
            return redirect()->route('user.wallet.deposit.form')->with('error', 'Authorize.Net deposits are currently disabled.');
        }

        $request->validate(['amount' => 'required|numeric|min:1']);
        $amount = (float) $request->input('amount');

        $apiLoginId = setting('authorizenet_login_id');
        $publicClientKey = setting('authorizenet_public_client_key');

        if (!$apiLoginId || !$publicClientKey) {
            Log::error("Authorize.Net wallet deposit form: API Login ID or Public Client Key is not set.");
            return redirect()->route('user.wallet.deposit.form')->with('error', 'Authorize.Net gateway is not configured correctly.');
        }

        return view('authorizenetgateway::wallet.deposit_form', compact('apiLoginId', 'publicClientKey', 'amount'));
    }

    public function processWalletDepositWithAcceptJs(Request $request)
    {
        if (setting('authorizenet_enabled', '0') != '1' || setting('allow_wallet_deposits', '0') != '1') {
            return redirect()->route('user.wallet.deposit.form')->with('error', 'Authorize.Net deposits are currently disabled.');
        }

        $request->validate([
            'amount' => 'required|numeric|min:1',
            'authorizenet_data_descriptor' => 'required|string',
            'authorizenet_data_value' => 'required|string', // Payment nonce
        ]);

        /** @var User $user */
        $user = Auth::user();
        $amount = (float) $request->input('amount');
        $currency = strtoupper(setting('currency_code', 'USD'));

        try {
            $opaqueData = [
                'dataDescriptor' => $request->input('authorizenet_data_descriptor'),
                'dataValue' => $request->input('authorizenet_data_value'),
            ];
            $customerDetails = ['email' => $user->email, 'firstName' => $user->name];
            $invoiceNumber = 'DEPOSIT-' . Str::random(6) . '-' . $user->id;
            $description = "Wallet Deposit for user {$user->id}";

            $response = $this->authorizeNetService->chargeCreditCard($amount, $opaqueData, $customerDetails, $invoiceNumber, $description);

            if ($response != null && $response->getMessages()->getResultCode() == "Ok" && $response->getTransactionResponse() != null && $response->getTransactionResponse()->getMessages() != null) {
                $transactionId = $response->getTransactionResponse()->getTransId();
                $this->walletService->deposit($user, $amount, $currency, 'authorizenetgateway', $transactionId, "Wallet deposit via Authorize.Net");
                return redirect()->route('user.wallet.history')->with('success', 'Successfully deposited ' . $currency . ' ' . number_format($amount, 2) . ' to your wallet.');
            }
            $errorMessage = $this->authorizeNetService->getErrorMessage($response);
            Log::error("Authorize.Net Wallet Deposit Error for user {$user->id}: " . $errorMessage, ['response' => $response]);
            return redirect()->route('wallet.authorizenet.depositForm', ['amount' => $amount])->with('error', 'Authorize.Net payment failed: ' . $errorMessage)->withInput();
        } catch (\Exception $e) {
            Log::error("Authorize.Net Wallet Deposit Exception for user {$user->id}: " . $e->getMessage());
            return redirect()->route('wallet.authorizenet.depositForm', ['amount' => $amount])->with('error', 'An error occurred while processing your deposit with Authorize.Net.')->withInput();
        }
    }
}


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\Http\Controllers\AuthorizeNetWebhookController.php ---
<?php

namespace Modules\AuthorizeNetGateway\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use net\authorize\api\contract\v1 as AnetAPI;
use net\authorize\api\controller as AnetController;
// ... other necessary models (Subscription, User, etc.)

class AuthorizeNetWebhookController extends Controller
{
    public function handle(Request $request)
    {
        $signatureKey = setting('authorizenet_signature_key');
        $payload = $request->getContent();
        $receivedSignature = $request->header('X-ANET-Signature');

        if (!$signatureKey) {
            Log::error('Authorize.Net Webhook: Signature key not configured.');
            return response()->json(['status' => 'error', 'message' => 'Configuration error'], 500);
        }

        // Verify signature
        $computedSignature = hash_hmac('sha512', $payload, hex2bin($signatureKey)); // Or just $signatureKey if it's not hex

        // Note: Authorize.Net's signature format might be "sha512=" prefix. Adjust as needed.
        // Example: $receivedSignature = str_replace('sha512=', '', $receivedSignature);

        if (!hash_equals(strtoupper($computedSignature), strtoupper($receivedSignature))) {
             Log::warning("Authorize.Net Webhook: Invalid signature. Received: {$receivedSignature}, Computed: {$computedSignature}");
             return response()->json(['status' => 'error', 'message' => 'Invalid signature'], 403);
        }

        $event = json_decode($payload, true);
        Log::info('Authorize.Net Webhook Received:', $event);

        $eventType = $event['eventType'] ?? null;
        $payloadData = $event['payload'] ?? null;

        switch ($eventType) {
            case 'net.authorize.payment.authcapture.created':
            case 'net.authorize.payment.capture.created':
                // Handle successful one-time payment
                // $transactionId = $payloadData['id'];
                // Potentially update an order or subscription status
                break;
            case 'net.authorize.customer.subscription.created':
            case 'net.authorize.customer.subscription.updated':
            case 'net.authorize.customer.subscription.cancelled':
            case 'net.authorize.customer.subscription.expiring':
            case 'net.authorize.customer.subscription.suspended':
            case 'net.authorize.customer.subscription.terminated':
                // Handle subscription events
                // $subscriptionId = $payloadData['id']; (This is Authorize.Net's subscription ID)
                // Find your local subscription record and update its status, ends_at, etc.
                break;
            // Add more cases as needed
            default:
                Log::info("Authorize.Net Webhook: Unhandled event type '{$eventType}'");
        }

        return response()->json(['status' => 'success'], 200);
    }
}



--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\Providers\AuthorizeNetGatewayServiceProvider.php ---
<?php

namespace Modules\AuthorizeNetGateway\Providers;

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use Nwidart\Modules\Traits\PathNamespace;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

class AuthorizeNetGatewayServiceProvider extends ServiceProvider
{
    use PathNamespace;

    protected string $name = 'AuthorizeNetGateway';

    protected string $nameLower = 'authorizenetgateway';

    /**
     * Boot the application events.
     */
    public function boot(): void
    {
        $this->registerCommands();
        $this->registerCommandSchedules();
        $this->registerTranslations();
        $this->registerConfig();
        $this->registerViews();
        $this->loadMigrationsFrom(module_path($this->name, 'database/migrations'));
    }

    /**
     * Register the service provider.
     */
    public function register(): void
    {
        $this->app->register(EventServiceProvider::class);
        $this->app->register(RouteServiceProvider::class);
    }

    /**
     * Register commands in the format of Command::class
     */
    protected function registerCommands(): void
    {
        // $this->commands([]);
    }

    /**
     * Register command Schedules.
     */
    protected function registerCommandSchedules(): void
    {
        // $this->app->booted(function () {
        //     $schedule = $this->app->make(Schedule::class);
        //     $schedule->command('inspire')->hourly();
        // });
    }

    /**
     * Register translations.
     */
    public function registerTranslations(): void
    {
        $langPath = resource_path('lang/modules/'.$this->nameLower);

        if (is_dir($langPath)) {
            $this->loadTranslationsFrom($langPath, $this->nameLower);
            $this->loadJsonTranslationsFrom($langPath);
        } else {
            $this->loadTranslationsFrom(module_path($this->name, 'lang'), $this->nameLower);
            $this->loadJsonTranslationsFrom(module_path($this->name, 'lang'));
        }
    }

    /**
     * Register config.
     */
    protected function registerConfig(): void
    {
        $configPath = module_path($this->name, config('modules.paths.generator.config.path'));

        if (is_dir($configPath)) {
            $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($configPath));

            foreach ($iterator as $file) {
                if ($file->isFile() && $file->getExtension() === 'php') {
                    $config = str_replace($configPath.DIRECTORY_SEPARATOR, '', $file->getPathname());
                    $config_key = str_replace([DIRECTORY_SEPARATOR, '.php'], ['.', ''], $config);
                    $segments = explode('.', $this->nameLower.'.'.$config_key);

                    // Remove duplicated adjacent segments
                    $normalized = [];
                    foreach ($segments as $segment) {
                        if (end($normalized) !== $segment) {
                            $normalized[] = $segment;
                        }
                    }

                    $key = ($config === 'config.php') ? $this->nameLower : implode('.', $normalized);

                    $this->publishes([$file->getPathname() => config_path($config)], 'config');
                    $this->merge_config_from($file->getPathname(), $key);
                }
            }
        }
    }

    /**
     * Merge config from the given path recursively.
     */
    protected function merge_config_from(string $path, string $key): void
    {
        $existing = config($key, []);
        $module_config = require $path;

        config([$key => array_replace_recursive($existing, $module_config)]);
    }

    /**
     * Register views.
     */
    public function registerViews(): void
    {
        $viewPath = resource_path('views/modules/'.$this->nameLower);
        $sourcePath = module_path($this->name, 'resources/views');

        $this->publishes([$sourcePath => $viewPath], ['views', $this->nameLower.'-module-views']);

        $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->nameLower);

        Blade::componentNamespace(config('modules.namespace').'\\' . $this->name . '\\View\\Components', $this->nameLower);
    }

    /**
     * Get the services provided by the provider.
     */
    public function provides(): array
    {
        return [];
    }

    private function getPublishableViewPaths(): array
    {
        $paths = [];
        foreach (config('view.paths') as $path) {
            if (is_dir($path.'/modules/'.$this->nameLower)) {
                $paths[] = $path.'/modules/'.$this->nameLower;
            }
        }

        return $paths;
    }
}


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\Providers\EventServiceProvider.php ---
<?php

namespace Modules\AuthorizeNetGateway\Providers;

use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event handler mappings for the application.
     *
     * @var array<string, array<int, string>>
     */
    protected $listen = [];

    /**
     * Indicates if events should be discovered.
     *
     * @var bool
     */
    protected static $shouldDiscoverEvents = true;

    /**
     * Configure the proper event listeners for email verification.
     */
    protected function configureEmailVerification(): void {}
}


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\Providers\RouteServiceProvider.php ---
<?php

namespace Modules\AuthorizeNetGateway\Providers;

use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
    protected string $name = 'AuthorizeNetGateway';

    /**
     * Called before routes are registered.
     *
     * Register any model bindings or pattern based filters.
     */
    public function boot(): void
    {
        parent::boot();
    }

    /**
     * Define the routes for the application.
     */
    public function map(): void
    {
        $this->mapApiRoutes();
        $this->mapWebRoutes();
    }

    /**
     * Define the "web" routes for the application.
     *
     * These routes all receive session state, CSRF protection, etc.
     */
    protected function mapWebRoutes(): void
    {
        Route::middleware('web')->group(module_path($this->name, '/routes/web.php'));
    }

    /**
     * Define the "api" routes for the application.
     *
     * These routes are typically stateless.
     */
    protected function mapApiRoutes(): void
    {
        Route::middleware('api')->prefix('api')->name('api.')->group(module_path($this->name, '/routes/api.php'));
    }
}


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\resources\views\admin\form\toggle-switch.blade.php ---
@props([
    'id',
    'name',
    'label',
    'value' => '1',
    'checked' => false,
    'helpText' => null,
])

<div>
    <label for="{{ $id }}" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">{{ $label }}</label>
    <label class="relative inline-flex items-center cursor-pointer mt-1">
        <input type="checkbox" id="{{ $id }}" name="{{ $name }}" class="sr-only peer" value="{{ $value }}" {{ $checked ? 'checked' : '' }} {{ $attributes }}>
        <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
        {{-- Optional: Text next to toggle if needed, passed via slot or another prop --}}
        {{-- <span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">Enabled</span> --}}
    </label>
    @if($helpText)
        <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">{{ $helpText }}</p>
    @endif
    @error($name) <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
</div>


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\resources\views\admin\config.blade.php ---
@extends('layouts.admin')

@section('title', 'Authorize.Net Gateway Settings')
@section('header_title', 'Authorize.Net Gateway Settings')

@section('content')
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-xl sm:rounded-lg">
    <div class="p-6 lg:p-8">
        @include('admin.partials.alerts') {{-- For success/error messages --}}

        <form action="{{ route('admin.authorizenetgateway.settings.update') }}" method="POST">
            @csrf
            @method('PUT')

            <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                <!-- Enable Authorize.Net -->
                <div class="md:col-span-2">
                    <label for="authorizenet_enabled" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Enable Authorize.Net Gateway</label>
                    <label class="relative inline-flex items-center cursor-pointer mt-1">
                        <input type="checkbox" id="authorizenet_enabled" name="authorizenet_enabled" class="sr-only peer" value="1" {{ old('authorizenet_enabled', $settings['authorizenet_enabled'] ?? '0') == '1' ? 'checked' : '' }}>
                        <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div>
                        <span class="ml-3 text-sm font-medium text-gray-900 dark:text-gray-300">
                            Enable Authorize.Net Gateway
                        </span>
                    </label>
                    <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
                        Toggle this to activate or deactivate the Authorize.Net payment gateway across the platform.
                    </p>
                    @error('authorizenet_enabled') <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
                </div>

                <!-- Authorize.Net Mode -->
                <div>
                    <label for="authorizenet_mode" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Authorize.Net Mode</label>
                    <select name="authorizenet_mode" id="authorizenet_mode" required
                            class="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md">
                        <option value="sandbox" {{ old('authorizenet_mode', $settings['authorizenet_mode'] ?? 'sandbox') == 'sandbox' ? 'selected' : '' }}>Sandbox (Test Environment)</option>
                        <option value="live" {{ old('authorizenet_mode', $settings['authorizenet_mode'] ?? '') == 'live' ? 'selected' : '' }}>Live (Production)</option>
                    </select>
                    @error('authorizenet_mode') <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
                </div>
                 <div></div> {{-- Spacer for grid --}}


                <!-- Authorize.Net API Login ID -->
                <div>
                    <label for="authorizenet_login_id" class="block text-sm font-medium text-gray-700 dark:text-gray-300">API Login ID</label>
                    <input type="text" name="authorizenet_login_id" id="authorizenet_login_id" value="{{ old('authorizenet_login_id', $settings['authorizenet_login_id'] ?? '') }}"
                           class="mt-1 block w-full shadow-sm sm:text-sm border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-md focus:ring-indigo-500 focus:border-indigo-500">
                    @error('authorizenet_login_id') <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
                </div>

                <!-- Authorize.Net Transaction Key -->
                <div>
                    <label for="authorizenet_transaction_key" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Transaction Key</label>
                    <input type="password" name="authorizenet_transaction_key" id="authorizenet_transaction_key" value="{{ old('authorizenet_transaction_key', $settings['authorizenet_transaction_key'] ?? '') }}"
                           class="mt-1 block w-full shadow-sm sm:text-sm border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-md focus:ring-indigo-500 focus:border-indigo-500">
                    @error('authorizenet_transaction_key') <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
                </div>

                <!-- Authorize.Net Public Client Key -->
                <div>
                    <label for="authorizenet_public_client_key" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Public Client Key</label>
                    <input type="text" name="authorizenet_public_client_key" id="authorizenet_public_client_key" value="{{ old('authorizenet_public_client_key', $settings['authorizenet_public_client_key'] ?? '') }}"
                           class="mt-1 block w-full shadow-sm sm:text-sm border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-md focus:ring-indigo-500 focus:border-indigo-500">
                    <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Used for Accept.js integration. Obtain this from your Authorize.Net Merchant Interface.</p>
                    @error('authorizenet_public_client_key') <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
                </div>
                <!-- Authorize.Net Signature Key (for Webhooks) -->
                <div>
                    <label for="authorizenet_signature_key" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Signature Key (for Webhooks)</label>
                    <input type="password" name="authorizenet_signature_key" id="authorizenet_signature_key" value="{{ old('authorizenet_signature_key', $settings['authorizenet_signature_key'] ?? '') }}"
                           class="mt-1 block w-full shadow-sm sm:text-sm border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-100 rounded-md focus:ring-indigo-500 focus:border-indigo-500">
                    <p class="mt-1 text-xs text-gray-500 dark:text-gray-400">Used to verify webhook signatures. Obtain this from your Authorize.Net Merchant Interface.</p>
                    @error('authorizenet_signature_key') <p class="mt-2 text-sm text-red-600 dark:text-red-400">{{ $message }}</p> @enderror
                </div>

            </div>

            <div class="mt-8 flex justify-end">
                <button type="submit" class="inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-200 border border-transparent rounded-md font-semibold text-xs text-white dark:text-gray-800 uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-white focus:bg-gray-700 dark:focus:bg-white active:bg-gray-900 dark:active:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800 transition ease-in-out duration-150">
                    Save Settings
                </button>
            </div>
        </form>
    </div>
</div>

@endsection


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\resources\views\components\layouts\master.blade.php ---
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">

        <title>AuthorizeNetGateway Module - {{ config('app.name', 'Laravel') }}</title>

        <meta name="description" content="{{ $description ?? '' }}">
        <meta name="keywords" content="{{ $keywords ?? '' }}">
        <meta name="author" content="{{ $author ?? '' }}">

        <!-- Fonts -->
        <link rel="preconnect" href="https://fonts.bunny.net">
        <link href="https://fonts.bunny.net/css?family=figtree:400,500,600&display=swap" rel="stylesheet" />

        {{-- Vite CSS --}}
        {{-- {{ module_vite('build-authorizenetgateway', 'resources/assets/sass/app.scss') }} --}}
    </head>

    <body>
        {{ $slot }}

        {{-- Vite JS --}}
        {{-- {{ module_vite('build-authorizenetgateway', 'resources/assets/js/app.js') }} --}}
    </body>


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\resources\views\subscriptions\checkout.blade.php ---
{{-- d:\projects\digitalvocano\Modules\AuthorizeNetGateway\Resources\views\subscriptions\checkout.blade.php --}}
<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Subscribe to :planName via Authorize.Net', ['planName' => $plan->name]) }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg p-6">
                <h3 class="text-lg font-medium text-gray-900">Plan: {{ $plan->name }}</h3>
                <p class="mt-1 text-sm text-gray-600">Price: ${{ number_format($plan->price, 2) }} / {{ $plan->interval }}</p>

                @if (session('error'))
                    <div class="mb-4 p-4 text-sm text-red-700 bg-red-100 rounded-lg" role="alert">
                        {{ session('error') }}
                    </div>
                @endif

                {{-- The action should point to your processing route --}}
                <form id="paymentForm"
                      action="{{ route('subscription.authorizenet.processSubscription', ['subscriptionPlan' => $plan->slug]) }}"
                      method="POST">
                    @csrf
                    <input type="hidden" name="dataValue" id="dataValue" />
                    <input type="hidden" name="dataDescriptor" id="dataDescriptor" />


                    <div class="mt-6">
                        <button type="button" id="AcceptUI"
                                class="AcceptUI inline-flex items-center px-4 py-2 bg-blue-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-blue-500 active:bg-blue-700 focus:outline-none focus:border-blue-700 focus:ring focus:ring-blue-200 disabled:opacity-25 transition"
                                data-billingAddressOptions='{"show":true, "required":false}'
                                data-apiLoginID="{{ $apiLoginId }}"
                                data-clientKey="{{ $publicClientKey }}"
                                data-acceptUIFormBtnTxt="Submit"
                                data-acceptUIFormHeaderTxt="Card Information"
                                data-responseHandler="responseHandler">Pay ${{ number_format($plan->price, 2) }}
                        </button>
                        {{-- Fallback submit button if AcceptUI button is not used or JS fails --}}
                        <button type="submit" id="submitPayment" style="display:none;">Submit Payment Data</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <script type="text/javascript"
        src="https://jstest.authorize.net/v1/AcceptUI.js"
        charset="utf-8">
    </script>
    {{-- Or for production:
    <script type="text/javascript"
        src="https://js.authorize.net/v1/AcceptUI.js"
        charset="utf-8">
    </script>
    --}}

    <script type="text/javascript">
        function responseHandler(response) {
            console.log("Authorize.Net responseHandler called with response:", response); // Add this line
            // alert("Response handler called!"); // Or use an alert for quick testing
            if (response.messages.resultCode === "Error") {
                var i = 0;
                let errorText = "";
                while (i < response.messages.message.length) {
                    console.log(
                        response.messages.message[i].code + ": " +
                        response.messages.message[i].text
                    );
                    errorText += response.messages.message[i].text + "<br/>";
                    i = i + 1;
                }
                // Display error to user, e.g., in an alert or a div
                alert("Payment Error: " + errorText.replace(/<br\/>/g, "\n"));
                // Re-enable the Pay button or allow retry
                document.getElementById("AcceptUI").disabled = false;

            } else {
                // Opaque data has been generated, set it to your hidden form fields
                document.getElementById("dataDescriptor").value = response.opaqueData.dataDescriptor;
                document.getElementById("dataValue").value = response.opaqueData.dataValue;

                // Disable the Pay button to prevent multiple submissions
                // document.getElementById("AcceptUI").disabled = true; // AcceptUI might handle this

                // Programmatically submit the form
                document.getElementById("paymentForm").submit();
            }
        }

        // Optional: If you are not using the AcceptUI button and building your own form with Accept.js
        // you would have a different button and use Accept.dispatchData instead.
        // For example:
        // document.getElementById('yourOwnSubmitButton').addEventListener('click', function() {
        //     var authData = {};
        //         authData.clientKey = "{{ $publicClientKey }}";
        //         authData.apiLoginID = "{{ $apiLoginId }}";
        //
        //     var cardData = {};
        //         cardData.cardNumber = document.getElementById('auth_card_number').value;
        //         cardData.month = document.getElementById('auth_exp_month').value;
        //         cardData.year = document.getElementById('auth_exp_year').value;
        //         cardData.cardCode = document.getElementById('auth_cvv').value;
        //
        //     var secureData = {};
        //         secureData.authData = authData;
        //         secureData.cardData = cardData;
        //
        //     Accept.dispatchData(secureData, responseHandler);
        // });
    </script>
</x-app-layout>


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\resources\views\wallet\deposit_form.blade.php ---
@extends('layouts.app') {{-- Or your main app layout --}}

@section('title', __('Deposit Funds with Authorize.Net'))

@section('content')
<div class="container mx-auto px-4 py-8">
    <div class="max-w-lg mx-auto bg-white dark:bg-gray-800 shadow-md rounded-lg p-6">
        <h1 class="text-2xl font-semibold text-gray-700 dark:text-gray-200 mb-6">{{ __('Deposit Funds') }}</h1>

        <div class="mb-4 p-4 border border-blue-300 dark:border-blue-700 bg-blue-50 dark:bg-blue-900 rounded">
            <p class="text-lg font-medium text-blue-700 dark:text-blue-300">{{ __('Amount to Deposit:') }} {{ setting('currency_symbol', '$') }}{{ number_format($amount, 2) }}</p>
        </div>

        @if(session('error'))
            <div class="mb-4 p-4 text-sm text-red-700 bg-red-100 rounded-lg dark:bg-red-200 dark:text-red-800" role="alert">
                {{ session('error') }}
            </div>
        @endif

        <form id="paymentForm"
            action="{{ route('wallet.authorizenet.processDeposit') }}"
            method="POST">
            @csrf
            <input type="hidden" name="amount" value="{{ $amount }}">

            {{-- Accept.js will populate these --}}
            <input type="hidden" name="authorizenet_data_descriptor" id="dataDescriptor" value="">
            <input type="hidden" name="authorizenet_data_value" id="dataValue" value="">

            {{-- Card Information Fields for Accept.js --}}
            <div class="mb-4">
                <label for="cardNumber" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('Card Number') }}</label>
                <input type="text" id="cardNumber" class="mt-1 block w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50" placeholder="•••• •••• •••• ••••" required>
            </div>

            <div class="grid grid-cols-2 gap-4 mb-4">
                <div>
                    <label for="expMonth" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('Expiration Month (MM)') }}</label>
                    <input type="text" id="expMonth" class="mt-1 block w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md shadow-sm" placeholder="MM" required>
                </div>
                <div>
                    <label for="expYear" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('Expiration Year (YYYY)') }}</label>
                    <input type="text" id="expYear" class="mt-1 block w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md shadow-sm" placeholder="YYYY" required>
                </div>
            </div>

            <div class="mb-6">
                <label for="cardCode" class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('CVV') }}</label>
                <input type="text" id="cardCode" class="mt-1 block w-full border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 rounded-md shadow-sm" placeholder="CVV" required>
            </div>

            <div class="flex justify-end">
                <button type="button" id="authorizePayButton"
                        class="inline-flex items-center px-4 py-2 bg-blue-600 hover:bg-blue-700 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition ease-in-out duration-150">
                    {{ __('Pay') }} {{ setting('currency_symbol', '$') }}{{ number_format($amount, 2) }}
                </button>
            </div>
        </form>
    </div>
</div>

<script type="text/javascript"
    src="{{ setting('authorizenet_mode', 'sandbox') == 'live' ? 'https://js.authorize.net/v1/Accept.js' : 'https://jstest.authorize.net/v1/Accept.js' }}"
    charset="utf-8">
</script>

<script type="text/javascript">
    document.addEventListener('DOMContentLoaded', function () {
        const payButton = document.getElementById('authorizePayButton');
        if (payButton) {
            payButton.addEventListener('click', function () {
                var secureData = {};
                var authData = {};
                    authData.clientKey = "{{ $publicClientKey }}";
                    authData.apiLoginID = "{{ $apiLoginId }}";

                var cardData = {};
                    cardData.cardNumber = document.getElementById('cardNumber').value;
                    cardData.month = document.getElementById('expMonth').value;
                    cardData.year = document.getElementById('expYear').value;
                    cardData.cardCode = document.getElementById('cardCode').value;
                secureData.cardData = cardData;
                secureData.authData = authData;

                Accept.dispatchData(secureData, function(response) { // responseHandler
                    if (response.messages.resultCode === "Error") {
                        var i = 0;
                        let errorText = "";
                        while (i < response.messages.message.length) {
                            errorText += response.messages.message[i].code + ":" + response.messages.message[i].text + "\n";
                            i = i + 1;
                        }
                        alert(errorText);
                    } else {
                        document.getElementById('dataDescriptor').value = response.opaqueData.dataDescriptor;
                        document.getElementById('dataValue').value = response.opaqueData.dataValue;
                        document.getElementById('paymentForm').submit();
                    }
                });
            });
        }
    });
</script>
@endsection


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\resources\views\index.blade.php ---
<x-authorizenetgateway::layouts.master>
    <h1>Hello World</h1>

    <p>Module: {!! config('authorizenetgateway.name') !!}</p>
</x-authorizenetgateway::layouts.master>


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\routes\admin.php ---
<?php

use Illuminate\Support\Facades\Route;
use Modules\AuthorizeNetGateway\Http\Controllers\Admin\AuthorizeNetConfigController;
use App\Http\Middleware\IsAdminMiddleware;

// The main app/Providers/RouteServiceProvider.php applies 'admin/authorizenetgateway/' prefix
// and 'admin.authorizenetgateway.' name prefix.
Route::middleware(['web', IsAdminMiddleware::class])
    ->group(function () {
        Route::get('settings', [AuthorizeNetConfigController::class, 'edit'])->name('settings.edit');
        Route::put('settings', [AuthorizeNetConfigController::class, 'update'])->name('settings.update');
    });


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\routes\api.php ---
<?php

use Illuminate\Support\Facades\Route;
use Modules\AuthorizeNetGateway\Http\Controllers\AuthorizeNetGatewayController;

Route::middleware(['auth:sanctum'])->prefix('v1')->group(function () {
    Route::apiResource('authorizenetgateways', AuthorizeNetGatewayController::class)->names('authorizenetgateway');
});


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\routes\web.php ---
<?php

use Illuminate\Support\Facades\Route;
// Remove if AuthorizeNetGatewayController is not used for user-facing actions
use Modules\AuthorizeNetGateway\Http\Controllers\AuthorizeNetWebhookController;
use Modules\AuthorizeNetGateway\Http\Controllers\AuthorizeNetSubscriptionController; // Added

// Webhook route for Authorize.Net notifications.
// This route should typically be exempt from CSRF protection.
Route::post('authorizenetgateway/webhook', [AuthorizeNetWebhookController::class, 'handle'])->name('authorizenetgateway.webhook');

Route::middleware(['web', 'auth']) // User must be authenticated
    ->prefix('subscribe/authorizenet')
    ->name('subscription.authorizenet.')
    ->group(function () {
        // The {subscriptionPlan:slug} will use route model binding
        // This route shows the form with Accept.js
        Route::get('checkout/{subscriptionPlan:slug}', [AuthorizeNetSubscriptionController::class, 'showCheckoutForm'])->name('checkout');
        // This route processes the payment nonce from Accept.js
        Route::post('process-subscription/{subscriptionPlan:slug}', [AuthorizeNetSubscriptionController::class, 'processSubscriptionWithAcceptJs'])->name('processSubscription');
    });

Route::middleware(['web', 'auth'])
    ->prefix('wallet/authorizenet')
    ->name('wallet.authorizenet.')
    ->group(function () {
        // The WalletController redirects to this route with amount in GET
        Route::get('deposit-form', [AuthorizeNetSubscriptionController::class, 'showWalletDepositForm'])->name('depositForm');
        Route::post('process-deposit', [AuthorizeNetSubscriptionController::class, 'processWalletDepositWithAcceptJs'])->name('processDeposit');
    });


--- File: D:\projects\digitalvocano\Modules\AuthorizeNetGateway\Services\AuthorizeNetService.php ---
<?php

namespace Modules\AuthorizeNetGateway\Services;

use Illuminate\Support\Facades\Log;
use net\authorize\api\contract\v1 as AnetAPI;
use net\authorize\api\controller as AnetController;

class AuthorizeNetService
{
    protected $merchantAuthentication;
    protected $endpoint;

    public function __construct()
    {
        if (!function_exists('setting')) {
            throw new \Exception("Settings helper function not found. Ensure it's globally available.");
        }

        $loginId = setting('authorizenet_login_id');
        $transactionKey = setting('authorizenet_transaction_key');
        $mode = setting('authorizenet_mode', 'sandbox');

        if (!$loginId || !$transactionKey) {
            Log::warning('Authorize.Net API Login ID or Transaction Key is not configured.');
            // Throw an exception to prevent using an uninitialized service.
            throw new \RuntimeException('Authorize.Net API Login ID or Transaction Key is not configured.');
        }

        $this->merchantAuthentication = new AnetAPI\MerchantAuthenticationType();
        $this->merchantAuthentication->setName($loginId);
        $this->merchantAuthentication->setTransactionKey($transactionKey);

        if ($mode === 'live') {
            $this->endpoint = \net\authorize\api\constants\ANetEnvironment::PRODUCTION;
        } else {
            $this->endpoint = \net\authorize\api\constants\ANetEnvironment::SANDBOX;
        }
    }

    public function getMerchantAuthentication()
    {
        return $this->merchantAuthentication;
    }

    public function getEndpoint()
    {
        return $this->endpoint;
    }

    /**
     * Charge a credit card.
     *
     * @param float $amount
     * @param array $opaqueDataOrCardDetails // If using Accept.js: ['dataDescriptor', 'dataValue']. If direct: ['cardNumber', 'expirationDate', 'cardCode']
     * @param array $customerDetails ['email', 'firstName', 'lastName', 'address', 'city', 'state', 'zip', 'country']
     * @param string $invoiceNumber Optional invoice number
     * @param string $description Optional description
     * @return AnetAPI\CreateTransactionResponse
     */
    public function chargeCreditCard(float $amount, array $opaqueDataOrCardDetails, array $customerDetails, string $invoiceNumber = null, string $description = null)
    {
        if (!$this->merchantAuthentication) {
            Log::error('Authorize.Net service not initialized properly. Merchant authentication missing.');
            // Create a mock error response or throw an exception
            $errorResponse = new AnetAPI\CreateTransactionResponse();
            $messages = new AnetAPI\MessagesType();
            $message = new AnetAPI\MessageType();
            $message->setCode("E00000"); // Generic error
            $message->setText("Authorize.Net service not configured.");
            $messages->setMessage([$message]);
            $errorResponse->setMessages($messages);
            return $errorResponse;
        }

        // Add the payment data to a paymentType object
        $paymentOne = new AnetAPI\PaymentType();

        // Check if we are using OpaqueData (Accept.js nonce) or direct card details
        if (isset($opaqueDataOrCardDetails['dataDescriptor']) && isset($opaqueDataOrCardDetails['dataValue'])) {
            $opaqueData = new AnetAPI\OpaqueDataType();
            $opaqueData->setDataDescriptor($opaqueDataOrCardDetails['dataDescriptor']);
            $opaqueData->setDataValue($opaqueDataOrCardDetails['dataValue']);
            $paymentOne->setOpaqueData($opaqueData);
        } else { // Fallback or direct card details (less secure, for previous compatibility if needed)
            $creditCard = new AnetAPI\CreditCardType();
            $creditCard->setCardNumber($opaqueDataOrCardDetails['cardNumber']);
            $creditCard->setExpirationDate($opaqueDataOrCardDetails['expirationDate']); // YYYY-MM
            $creditCard->setCardCode($opaqueDataOrCardDetails['cardCode'] ?? null);
            $paymentOne->setCreditCard($creditCard);
            Log::warning('AuthorizeNetService: Processing payment with direct card details. Consider Accept.js for PCI compliance.');
        }

        // Create order information if provided
        $order = null;
        if ($invoiceNumber || $description) {
            $order = new AnetAPI\OrderType();
            if ($invoiceNumber) {
                $order->setInvoiceNumber($invoiceNumber);
            }
            if ($description) {
                $order->setDescription($description);
            }
        }

        // Set the customer's Bill To address
        $customerAddress = new AnetAPI\CustomerAddressType();
        $customerAddress->setFirstName($customerDetails['firstName'] ?? null);
        $customerAddress->setLastName($customerDetails['lastName'] ?? null);
        $customerAddress->setAddress($customerDetails['address'] ?? null);
        $customerAddress->setCity($customerDetails['city'] ?? null);
        $customerAddress->setState($customerDetails['state'] ?? null);
        $customerAddress->setZip($customerDetails['zip'] ?? null);
        $customerAddress->setCountry($customerDetails['country'] ?? 'USA'); // Default or make required

        // Set the customer's email
        $customerData = new AnetAPI\CustomerDataType();
        $customerData->setEmail($customerDetails['email'] ?? null);

        // Create a transaction
        $transactionRequestType = new AnetAPI\TransactionRequestType();
        $transactionRequestType->setTransactionType("authCaptureTransaction"); // Or "authOnlyTransaction"
        $transactionRequestType->setAmount($amount);
        $transactionRequestType->setPayment($paymentOne);
        if ($order) {
            $transactionRequestType->setOrder($order);
        }
        $transactionRequestType->setBillTo($customerAddress);
        $transactionRequestType->setCustomer($customerData);

        $request = new AnetAPI\CreateTransactionRequest();
        $request->setMerchantAuthentication($this->getMerchantAuthentication());
        $request->setTransactionRequest($transactionRequestType);

        $controller = new AnetController\CreateTransactionController($request);
        return $controller->executeWithApiResponse($this->getEndpoint());
    }
}


