<?php

declare(strict_types=1);

namespace App\Services\Provisioning;

use App\Models\ProvisioningLog;
use App\Models\Service;
use App\Notifications\ServiceCredentialsNotification;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Laravel\Cashier\Subscription;
use RuntimeException;

class VirtFusionService implements ProvisioningServiceInterface
{
    private readonly string $baseUrl;

    private readonly string $token;

    private ?string $csrfToken = null;

    public function __construct()
    {
        // Read from database settings (configured via admin panel)
        $this->baseUrl = rtrim(\App\Models\Setting::get('virtfusion_api_url', ''), '/');
        $this->token = \App\Models\Setting::get('virtfusion_api_token', '');

        if (empty($this->baseUrl)) {
            throw new RuntimeException('VirtFusion API URL is not configured. Please configure it in Admin → Settings → API.');
        }

        if (empty($this->token)) {
            throw new RuntimeException('VirtFusion API token is not configured. Please configure it in Admin → Settings → API.');
        }
    }

    private function getCsrfToken(): string
    {
        if ($this->csrfToken !== null) {
            return $this->csrfToken;
        }

        try {
            // Fetch CSRF token from VirtFusion API
            $response = Http::withToken($this->token)
                ->baseUrl($this->baseUrl)
                ->get('/sanctum/csrf-cookie');

            // Extract CSRF token from cookies if available
            $cookies = $response->cookies();
            foreach ($cookies as $cookie) {
                if ($cookie->getName() === 'XSRF-TOKEN') {
                    $this->csrfToken = $cookie->getValue();

                    return $this->csrfToken;
                }
            }

            // If no CSRF endpoint exists, return empty string (token-based auth only)
            $this->csrfToken = '';

            return $this->csrfToken;
        } catch (\Exception $e) {
            Log::warning('Failed to fetch CSRF token from VirtFusion', [
                'error' => $e->getMessage(),
            ]);

            $this->csrfToken = '';

            return $this->csrfToken;
        }
    }

    public function provision(Subscription $subscription): Service
    {
        $user = $subscription->user;
        $plan = \App\Models\Plan::find($subscription->plan_id);

        if (! $plan) {
            throw new RuntimeException('Subscription has no associated plan.');
        }

        $service = Service::firstOrCreate(
            ['subscription_id' => $subscription->id, 'service_type' => 'vps'],
            [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'platform' => 'virtfusion',
                'status' => 'pending',
            ],
        );

        if ($service->status === 'failed') {
            $service->update(['status' => 'pending']);
        }

        $this->logAction($service, 'provision', 'pending');

        try {
            // Ensure user exists on VirtFusion panel
            $virtfusionUserId = $this->ensureUserExists($user);

            // Get provisioning config from the plan (package_id, hypervisor_id, etc.)
            $provConfig = $plan->provisioning_config ?? [];
            $packageId = $provConfig['package_id'] ?? null;
            $hypervisorId = $provConfig['hypervisor_id'] ?? 1;

            if (! $packageId) {
                throw new RuntimeException('Plan does not have a VirtFusion package configured. Set package_id in the plan\'s provisioning config.');
            }

            // Get configuration for OS template and SSH keys from the subscription record
            $rawConfig = $subscription->provisioning_config;
            $config = is_string($rawConfig) ? json_decode($rawConfig, true) ?? [] : ($rawConfig ?? []);
            $operatingSystemId = $config['os_template_id'] ?? 1;
            $authMethod = $config['auth_method'] ?? 'password';
            $sshKey = $authMethod === 'ssh' && ! empty($config['ssh_key']) ? $config['ssh_key'] : null;

            // Step 1: Create SSH key in VirtFusion if provided (to get SSH key ID)
            $sshKeyIds = [];
            if ($sshKey) {
                $sshKeyId = $this->createSshKey($virtfusionUserId, $sshKey);
                if ($sshKeyId) {
                    $sshKeyIds[] = $sshKeyId;
                    Log::info('Created SSH key in VirtFusion', [
                        'ssh_key_id' => $sshKeyId,
                        'user_id' => $virtfusionUserId,
                    ]);
                }
            }

            // Step 2: Create server using VirtFusion package (specs are defined in the package)
            $createPayload = [
                'userId' => $virtfusionUserId,
                'packageId' => $packageId,
                'hypervisorId' => $hypervisorId,
            ];

            $createResponse = $this->client()->post('/servers', $createPayload);

            if (! $createResponse->successful()) {
                $this->logAction($service, 'provision', 'failed', $createResponse->json(), $createResponse->body());
                throw new RuntimeException("VirtFusion server creation failed: {$createResponse->body()}");
            }

            $createData = $createResponse->json();
            $serverId = (string) ($createData['data']['id'] ?? $createData['id'] ?? '');

            if (empty($serverId)) {
                throw new RuntimeException('VirtFusion returned invalid server ID');
            }

            Log::info('VirtFusion server created', [
                'service_id' => $service->id,
                'server_id' => $serverId,
                'package_id' => $packageId,
            ]);

            // Step 3: Build server with OS template and SSH keys
            $buildPayload = [
                'operatingSystemId' => $operatingSystemId,
            ];

            if (! empty($sshKeyIds)) {
                $buildPayload['sshKeys'] = $sshKeyIds;
            }

            $buildResponse = $this->client()->post("/servers/{$serverId}/build", $buildPayload);

            if (! $buildResponse->successful()) {
                $this->logAction($service, 'build', 'failed', $buildResponse->json(), $buildResponse->body());
                Log::warning('VirtFusion build failed but server was created', [
                    'service_id' => $service->id,
                    'server_id' => $serverId,
                    'error' => $buildResponse->body(),
                ]);
                // Continue anyway - server exists, user can rebuild manually
            } else {
                $buildData = $buildResponse->json();
                $this->logAction($service, 'build', 'success', $buildData);
                Log::info('VirtFusion server built', [
                    'service_id' => $service->id,
                    'server_id' => $serverId,
                    'os_id' => $operatingSystemId,
                    'ssh_keys_count' => count($sshKeyIds),
                ]);
            }

            // Update service with provisioned data
            // Store provisioning info in the credentials column (JSON cast)
            // since provisioning_info is an accessor that reads from credentials
            $existingCredentials = $service->credentials ?? [];
            $service->update([
                'platform_service_id' => $serverId,
                'status' => 'active',
                'ipv4_address' => $createData['data']['ip_address'] ?? $createData['ip_address'] ?? null,
                'hostname' => $createData['data']['hostname'] ?? $createData['hostname'] ?? null,
                'provisioned_at' => now(),
                'credentials' => array_merge($existingCredentials, [
                    'os_template_id' => $operatingSystemId,
                    'auth_method' => $config['auth_method'] ?? 'password',
                    'package_id' => $packageId,
                    'ssh_key_ids' => $sshKeyIds,
                ]),
            ]);

            $this->logAction($service, 'provision', 'success', $createData);

            $service = $service->fresh();

            // Send credentials notification
            if ($service->user) {
                $service->user->notify(new ServiceCredentialsNotification($service, [
                    'username' => $createData['data']['username'] ?? 'root',
                    'password' => $createData['data']['password'] ?? 'Check VirtFusion panel',
                    'hostname' => $service->hostname ?? $service->ipv4_address ?? 'N/A',
                    'ip_address' => $service->ipv4_address ?? 'Pending',
                    'port' => $createData['data']['ssh_port'] ?? 22,
                    'panel_url' => $createData['data']['vnc_url'] ?? null,
                ]));
            }

            return $service;
        } catch (\Exception $e) {
            $this->logAction($service, 'provision', 'failed', errorMessage: $e->getMessage());

            $service->update(['status' => 'failed']);

            throw new RuntimeException("VirtFusion provisioning error: {$e->getMessage()}", 0, $e);
        }
    }

    public function suspend(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'suspend', 'pending');

        try {
            $response = $this->client()->post("/servers/{$service->platform_service_id}/suspend");

            if (! $response->successful()) {
                $this->logAction($service, 'suspend', 'failed', $response->json(), $response->body());

                return false;
            }

            $service->update([
                'status' => 'suspended',
                'suspended_at' => now(),
            ]);

            $this->logAction($service, 'suspend', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('VirtFusion suspend failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'suspend', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    public function unsuspend(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'unsuspend', 'pending');

        try {
            $response = $this->client()->post("/servers/{$service->platform_service_id}/unsuspend");

            if (! $response->successful()) {
                $this->logAction($service, 'unsuspend', 'failed', $response->json(), $response->body());

                return false;
            }

            $service->update([
                'status' => 'active',
                'suspended_at' => null,
            ]);

            $this->logAction($service, 'unsuspend', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('VirtFusion unsuspend failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'unsuspend', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    public function terminate(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'terminate', 'pending');

        try {
            // Delete with 5-minute delay (300 seconds)
            $response = $this->client()->delete("/servers/{$service->platform_service_id}", [
                'delay' => 300,
            ]);

            if (! $response->successful()) {
                $this->logAction($service, 'terminate', 'failed', $response->json(), $response->body());

                return false;
            }

            $service->update([
                'status' => 'terminated',
                'terminated_at' => now(),
            ]);

            $this->logAction($service, 'terminate', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('VirtFusion terminate failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'terminate', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    /**
     * @return array{status: string, ip_address?: string, hostname?: string, platform_data?: array<string, mixed>}
     */
    public function getStatus(Service $service): array
    {
        $this->validateServicePlatform($service);

        try {
            $response = $this->client()->get("/servers/{$service->platform_service_id}");

            if (! $response->successful()) {
                return ['status' => 'unknown'];
            }

            $data = $response->json();
            $serverData = $data['data'] ?? $data;

            return [
                'status' => $serverData['status'] ?? 'unknown',
                'ip_address' => $serverData['ip_address'] ?? $service->ipv4_address,
                'hostname' => $serverData['hostname'] ?? $service->hostname,
                'platform_data' => $serverData,
            ];
        } catch (\Exception $e) {
            Log::error('VirtFusion getStatus failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return ['status' => 'unknown'];
        }
    }

    /**
     * @return array{username?: string, password?: string, url?: string, additional?: array<string, mixed>}
     */
    public function getCredentials(Service $service): array
    {
        $this->validateServicePlatform($service);

        $stored = $service->credentials ?? [];

        try {
            $response = $this->client()->get("/servers/{$service->platform_service_id}");

            if ($response->successful()) {
                $data = $response->json();
                $serverData = $data['data'] ?? $data;

                return [
                    'username' => $stored['username'] ?? 'root',
                    'password' => $stored['password'] ?? null,
                    'url' => $serverData['vnc_url'] ?? null,
                    'additional' => [
                        'ip_address' => $serverData['ip_address'] ?? $service->ipv4_address,
                        'hostname' => $serverData['hostname'] ?? $service->hostname,
                    ],
                ];
            }
        } catch (\Exception $e) {
            Log::error('VirtFusion getCredentials failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);
        }

        return [
            'username' => $stored['username'] ?? 'root',
            'password' => $stored['password'] ?? null,
        ];
    }

    private function client(): PendingRequest
    {
        $client = Http::withToken($this->token)
            ->baseUrl($this->baseUrl)
            ->acceptJson()
            ->timeout(30);

        // Add CSRF token header if available
        $csrfToken = $this->getCsrfToken();
        if (! empty($csrfToken)) {
            $client = $client->withHeaders([
                'X-XSRF-TOKEN' => $csrfToken,
            ]);
        }

        return $client;
    }

    private function validateServicePlatform(Service $service): void
    {
        if (! $service->platform_service_id) {
            throw new RuntimeException('Service has no platform service ID.');
        }
    }

    public function boot(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'boot', 'pending');

        try {
            $response = $this->client()->post("/servers/{$service->platform_service_id}/power/boot");

            if (! $response->successful()) {
                $this->logAction($service, 'boot', 'failed', $response->json(), $response->body());

                return false;
            }

            $this->logAction($service, 'boot', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('VirtFusion boot failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'boot', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    public function shutdown(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'shutdown', 'pending');

        try {
            $response = $this->client()->post("/servers/{$service->platform_service_id}/power/shutdown");

            if (! $response->successful()) {
                $this->logAction($service, 'shutdown', 'failed', $response->json(), $response->body());

                return false;
            }

            $this->logAction($service, 'shutdown', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('VirtFusion shutdown failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'shutdown', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    public function restart(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'restart', 'pending');

        try {
            $response = $this->client()->post("/servers/{$service->platform_service_id}/power/restart");

            if (! $response->successful()) {
                $this->logAction($service, 'restart', 'failed', $response->json(), $response->body());

                return false;
            }

            $this->logAction($service, 'restart', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('VirtFusion restart failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'restart', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    public function poweroff(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'poweroff', 'pending');

        try {
            $response = $this->client()->post("/servers/{$service->platform_service_id}/power/poweroff");

            if (! $response->successful()) {
                $this->logAction($service, 'poweroff', 'failed', $response->json(), $response->body());

                return false;
            }

            $this->logAction($service, 'poweroff', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('VirtFusion poweroff failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'poweroff', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    /**
     * @return array{password?: string, username?: string}
     */
    public function resetPassword(Service $service): array
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'reset_password', 'pending');

        try {
            $response = $this->client()->post("/servers/{$service->platform_service_id}/resetPassword");

            if (! $response->successful()) {
                $this->logAction($service, 'reset_password', 'failed', $response->json(), $response->body());

                throw new RuntimeException("Failed to reset password: {$response->body()}");
            }

            $data = $response->json();
            $this->logAction($service, 'reset_password', 'success', $data);

            return [
                'password' => $data['data']['password'] ?? $data['password'] ?? null,
                'username' => $data['data']['username'] ?? $data['username'] ?? 'root',
            ];
        } catch (RuntimeException $e) {
            throw $e;
        } catch (\Exception $e) {
            Log::error('VirtFusion reset password failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'reset_password', 'failed', errorMessage: $e->getMessage());

            throw new RuntimeException("Failed to reset password: {$e->getMessage()}", 0, $e);
        }
    }

    public function getVncUrl(Service $service): ?string
    {
        $this->validateServicePlatform($service);

        try {
            $response = $this->client()->get("/servers/{$service->platform_service_id}/vnc");

            if (! $response->successful()) {
                Log::warning('VirtFusion get VNC URL failed', [
                    'service_id' => $service->id,
                    'response' => $response->body(),
                ]);

                return null;
            }

            $data = $response->json();

            return $data['data']['url'] ?? $data['url'] ?? null;
        } catch (\Exception $e) {
            Log::error('VirtFusion get VNC URL failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    public function rebuild(Service $service, int $operatingSystemId): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'rebuild', 'pending');

        try {
            $response = $this->client()->post("/servers/{$service->platform_service_id}/build", [
                'operatingSystemId' => $operatingSystemId,
            ]);

            if (! $response->successful()) {
                $this->logAction($service, 'rebuild', 'failed', $response->json(), $response->body());

                return false;
            }

            $this->logAction($service, 'rebuild', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('VirtFusion rebuild failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'rebuild', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    /**
     * @return array<int, array<string, mixed>>
     */
    public function getTemplates(Service $service): array
    {
        $this->validateServicePlatform($service);

        try {
            $response = $this->client()->get("/servers/{$service->platform_service_id}/templates");

            if (! $response->successful()) {
                Log::warning('VirtFusion get templates failed', [
                    'service_id' => $service->id,
                    'response' => $response->body(),
                ]);

                return [];
            }

            $data = $response->json();

            return $data['data'] ?? [];
        } catch (\Exception $e) {
            Log::error('VirtFusion get templates failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return [];
        }
    }

    /**
     * Get first available package ID from VirtFusion.
     */
    private function getFirstAvailablePackageId(): ?int
    {
        try {
            $response = $this->client()->get('/packages');

            if (! $response->successful()) {
                return null;
            }

            $data = $response->json();
            $packages = $data['data'] ?? [];

            return ! empty($packages) ? (int) $packages[0]['id'] : null;
        } catch (\Exception $e) {
            Log::error('Failed to fetch VirtFusion packages', [
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    /**
     * Get all available OS templates from VirtFusion by package ID.
     *
     * @return array{groups: array<int, array<string, mixed>>, templates: array<int, array<string, mixed>>}
     */
    public function getTemplatesByPackage(?int $packageId = null): array
    {
        try {
            // If no package ID provided, get the first available package
            if ($packageId === null) {
                $packageId = $this->getFirstAvailablePackageId();
                if ($packageId === null) {
                    Log::warning('No VirtFusion packages available');

                    return ['groups' => [], 'templates' => []];
                }
            }

            // Fetch templates for specific package
            $response = $this->client()->get("/media/templates/fromServerPackageSpec/{$packageId}");

            if (! $response->successful()) {
                Log::warning('VirtFusion get templates by package failed', [
                    'package_id' => $packageId,
                    'response' => $response->body(),
                ]);

                // If the package doesn't exist, try the first available package
                if ($response->status() === 404) {
                    $fallbackPackageId = $this->getFirstAvailablePackageId();
                    if ($fallbackPackageId !== null && $fallbackPackageId !== $packageId) {
                        return $this->getTemplatesByPackage($fallbackPackageId);
                    }
                }

                return ['groups' => [], 'templates' => []];
            }

            $data = $response->json();
            $templateGroups = $data['data'] ?? [];

            // Flatten the nested structure - extract all templates from all OS families
            $allTemplates = [];
            foreach ($templateGroups as $group) {
                if (isset($group['templates']) && is_array($group['templates'])) {
                    foreach ($group['templates'] as $template) {
                        $allTemplates[] = $template;
                    }
                }
            }

            // Return both grouped and flattened data
            return [
                'groups' => $templateGroups,
                'templates' => $allTemplates,
            ];
        } catch (\Exception $e) {
            Log::error('VirtFusion get templates by package failed', [
                'package_id' => $packageId,
                'error' => $e->getMessage(),
            ]);

            return ['groups' => [], 'templates' => []];
        }
    }

    /**
     * Get all available OS templates from VirtFusion (legacy method - use getTemplatesByPackage instead).
     *
     * @return array<int, array<string, mixed>>
     */
    public function getAllTemplates(int $packageId = 1): array
    {
        // Deprecated: use getTemplatesByPackage instead
        return $this->getTemplatesByPackage($packageId);
    }

    /**
     * Create SSH key in VirtFusion and return its ID.
     */
    private function createSshKey(int $virtfusionUserId, string $publicKey): ?int
    {
        try {
            $response = $this->client()->post('/sshkeys', [
                'userId' => $virtfusionUserId,
                'name' => 'VPS Key - '.now()->format('Y-m-d H:i:s'),
                'publicKey' => trim($publicKey),
            ]);

            if (! $response->successful()) {
                Log::warning('Failed to create SSH key in VirtFusion', [
                    'user_id' => $virtfusionUserId,
                    'response' => $response->body(),
                ]);

                return null;
            }

            $data = $response->json();
            $sshKeyId = (int) ($data['data']['id'] ?? $data['id'] ?? 0);

            return $sshKeyId > 0 ? $sshKeyId : null;
        } catch (\Exception $e) {
            Log::error('Exception creating SSH key in VirtFusion', [
                'user_id' => $virtfusionUserId,
                'error' => $e->getMessage(),
            ]);

            return null;
        }
    }

    /**
     * Ensure user exists on VirtFusion panel, create if not.
     * Uses extRelationId (our local user ID) to link VF users to our system.
     */
    private function ensureUserExists(\App\Models\User $user): int
    {
        // Fast path: already have the VF user ID cached locally
        if ($user->virtfusion_user_id) {
            return $user->virtfusion_user_id;
        }

        // Try to find user by extRelationId (our local user ID)
        $existingUserId = $this->findUserByExtRelation($user->id);
        if ($existingUserId) {
            $user->update(['virtfusion_user_id' => $existingUserId]);

            return $existingUserId;
        }

        // User doesn't exist, create them with extRelationId set to our local user ID
        try {
            $response = $this->client()->post('/users', [
                'name' => $user->name,
                'email' => $user->email,
                'password' => bin2hex(random_bytes(16)),
                'confirmed' => true,
                'extRelationId' => $user->id,
            ]);

            if (! $response->successful()) {
                $responseBody = $response->body();

                // If user already exists (email conflict), try to look them up by extRelationId
                if (str_contains($responseBody, 'already exists')) {
                    // The user exists but wasn't linked via extRelationId — try all VF users
                    // Since there's no email search endpoint, we need to set the extRelationId
                    // on the existing VF user. For now, log and throw a helpful error.
                    Log::warning('VirtFusion user exists but not linked via extRelationId', [
                        'email' => $user->email,
                        'local_user_id' => $user->id,
                    ]);

                    throw new RuntimeException(
                        "VirtFusion user with email {$user->email} already exists but is not linked. "
                        .'Please set extRelationId to '.$user->id.' on the VirtFusion user, '
                        .'or delete the VirtFusion user and retry.'
                    );
                }

                Log::error('Failed to create VirtFusion user', [
                    'email' => $user->email,
                    'response' => $responseBody,
                ]);

                throw new RuntimeException("Failed to create VirtFusion user: {$responseBody}");
            }

            $data = $response->json();
            $userId = (int) ($data['data']['id'] ?? $data['id'] ?? 0);

            if ($userId > 0) {
                $user->update(['virtfusion_user_id' => $userId]);
                Log::info('Created VirtFusion user', [
                    'email' => $user->email,
                    'virtfusion_user_id' => $userId,
                    'extRelationId' => $user->id,
                ]);

                return $userId;
            }

            throw new RuntimeException('VirtFusion user creation returned invalid user ID');
        } catch (RuntimeException $e) {
            throw $e;
        } catch (\Exception $e) {
            Log::error('Exception creating VirtFusion user', [
                'email' => $user->email,
                'error' => $e->getMessage(),
            ]);

            throw new RuntimeException("Failed to create VirtFusion user: {$e->getMessage()}", 0, $e);
        }
    }

    /**
     * Look up a VirtFusion user by extRelationId (our local user ID).
     */
    private function findUserByExtRelation(int $extRelationId): ?int
    {
        try {
            $response = $this->client()->get("/users/{$extRelationId}/byExtRelation");

            if ($response->successful()) {
                $data = $response->json();

                return (int) ($data['data']['id'] ?? 0) ?: null;
            }
        } catch (\Exception $e) {
            Log::warning('Failed to find VirtFusion user by extRelation', [
                'extRelationId' => $extRelationId,
                'error' => $e->getMessage(),
            ]);
        }

        return null;
    }

    /**
     * @param  array<string, mixed>|null  $response
     */
    private function logAction(
        Service $service,
        string $action,
        string $status,
        ?array $response = null,
        ?string $errorMessage = null,
    ): void {
        ProvisioningLog::create([
            'service_id' => $service->id,
            'user_id' => $service->user_id,
            'action' => $action,
            'platform' => 'virtfusion',
            'platform_response' => $response,
            'status' => $status,
            'error_message' => $errorMessage,
        ]);
    }
}
