<?php

declare(strict_types=1);

namespace App\Http\Controllers\Account;

use App\Http\Controllers\Controller;
use App\Http\Requests\Account\RebuildVpsRequest;
use App\Models\AuditLog;
use App\Models\Service;
use App\Services\Provisioning\VirtFusionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class VpsController extends Controller
{
    public function __construct(
        private readonly VirtFusionService $virtfusion,
    ) {}

    public function boot(Request $request, Service $service): RedirectResponse
    {
        $this->authorizeServiceAccess($request, $service);

        try {
            $success = $this->virtfusion->boot($service);

            $this->logAudit($request, $service, 'vps_boot', $success);

            if ($success) {
                return redirect()->back()->with('success', 'VPS boot initiated successfully.');
            }

            return redirect()->back()->with('error', 'Failed to boot VPS. Please try again or contact support.');
        } catch (\Exception $e) {
            Log::error('VPS boot controller error', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return redirect()->back()->with('error', 'An error occurred while booting the VPS.');
        }
    }

    public function shutdown(Request $request, Service $service): RedirectResponse
    {
        $this->authorizeServiceAccess($request, $service);

        try {
            $success = $this->virtfusion->shutdown($service);

            $this->logAudit($request, $service, 'vps_shutdown', $success);

            if ($success) {
                return redirect()->back()->with('success', 'VPS shutdown initiated successfully.');
            }

            return redirect()->back()->with('error', 'Failed to shutdown VPS. Please try again or contact support.');
        } catch (\Exception $e) {
            Log::error('VPS shutdown controller error', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return redirect()->back()->with('error', 'An error occurred while shutting down the VPS.');
        }
    }

    public function restart(Request $request, Service $service): RedirectResponse
    {
        $this->authorizeServiceAccess($request, $service);

        try {
            $success = $this->virtfusion->restart($service);

            $this->logAudit($request, $service, 'vps_restart', $success);

            if ($success) {
                return redirect()->back()->with('success', 'VPS restart initiated successfully.');
            }

            return redirect()->back()->with('error', 'Failed to restart VPS. Please try again or contact support.');
        } catch (\Exception $e) {
            Log::error('VPS restart controller error', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return redirect()->back()->with('error', 'An error occurred while restarting the VPS.');
        }
    }

    public function poweroff(Request $request, Service $service): RedirectResponse
    {
        $this->authorizeServiceAccess($request, $service);

        try {
            $success = $this->virtfusion->poweroff($service);

            $this->logAudit($request, $service, 'vps_poweroff', $success);

            if ($success) {
                return redirect()->back()->with('success', 'VPS power off initiated successfully.');
            }

            return redirect()->back()->with('error', 'Failed to power off VPS. Please try again or contact support.');
        } catch (\Exception $e) {
            Log::error('VPS poweroff controller error', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return redirect()->back()->with('error', 'An error occurred while powering off the VPS.');
        }
    }

    public function resetPassword(Request $request, Service $service): RedirectResponse
    {
        $this->authorizeServiceAccess($request, $service);

        try {
            $result = $this->virtfusion->resetPassword($service);

            $this->logAudit($request, $service, 'vps_reset_password', ! empty($result));

            if (! empty($result['password'])) {
                return redirect()->back()
                    ->with('new_password', $result['password'])
                    ->with('success', 'Root password reset successfully.');
            }

            return redirect()->back()->with('error', 'Failed to reset password. Please try again or contact support.');
        } catch (\Exception $e) {
            Log::error('VPS reset password controller error', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return redirect()->back()->with('error', 'An error occurred while resetting the password.');
        }
    }

    public function vnc(Request $request, Service $service): JsonResponse
    {
        $this->authorizeServiceAccess($request, $service);

        try {
            $url = $this->virtfusion->getVncUrl($service);

            if ($url) {
                return response()->json([
                    'success' => true,
                    'url' => $url,
                ]);
            }

            return response()->json([
                'success' => false,
                'message' => 'VNC console is not available.',
            ], 404);
        } catch (\Exception $e) {
            Log::error('VPS VNC controller error', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while fetching the VNC console.',
            ], 500);
        }
    }

    public function templates(Request $request, Service $service): JsonResponse
    {
        $this->authorizeServiceAccess($request, $service);

        try {
            $templates = $this->virtfusion->getTemplates($service);

            return response()->json([
                'success' => true,
                'templates' => $templates,
            ]);
        } catch (\Exception $e) {
            Log::error('VPS templates controller error', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while fetching templates.',
            ], 500);
        }
    }

    public function rebuild(RebuildVpsRequest $request, Service $service): RedirectResponse
    {
        $this->authorizeServiceAccess($request, $service);

        try {
            $success = $this->virtfusion->rebuild($service, $request->validated()['template_id']);

            $this->logAudit($request, $service, 'vps_rebuild', $success, [
                'template_id' => $request->validated()['template_id'],
            ]);

            if ($success) {
                return redirect()->back()->with('success', 'VPS rebuild initiated successfully. This may take several minutes.');
            }

            return redirect()->back()->with('error', 'Failed to rebuild VPS. Please try again or contact support.');
        } catch (\Exception $e) {
            Log::error('VPS rebuild controller error', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return redirect()->back()->with('error', 'An error occurred while rebuilding the VPS.');
        }
    }

    private function authorizeServiceAccess(Request $request, Service $service): void
    {
        abort_unless($service->user_id === $request->user()->id, 403);
        abort_unless($service->platform === 'virtfusion', 403, 'This service is not a VirtFusion VPS.');
        abort_unless($service->status === 'active', 403, 'This VPS is not active.');
    }

    /**
     * @param  array<string, mixed>  $changes
     */
    private function logAudit(Request $request, Service $service, string $action, bool $success, array $changes = []): void
    {
        AuditLog::create([
            'user_id' => $request->user()->id,
            'action' => $action,
            'resource_type' => 'service',
            'resource_id' => $service->id,
            'ip_address' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'changes' => array_merge($changes, [
                'success' => $success,
                'service_id' => $service->id,
                'platform' => $service->platform,
            ]),
        ]);
    }
}
