<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Services\QzTray\CertificateService;
use App\Services\QzTray\SigningService;
use App\Repositories\QzTrayLog\QzTrayLogRepositoryInterface;
use App\Http\Requests\QzTray\GenerateCertificateRequest;
use App\Http\Requests\QzTray\SignPayloadRequest;
use App\Events\QzTray\CertificateGenerated;
use App\Events\QzTray\CertificateRegenerated;
use App\Events\QzTray\CertificateDeleted;
use App\Events\QzTray\PayloadSigned;
use App\Events\QzTray\SigningFailed;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Gate;
use Inertia\Inertia;
use Inertia\Response;

class QzTrayController extends Controller
{
    public function __construct(
        protected CertificateService $certificateService,
        protected SigningService $signingService,
        protected QzTrayLogRepositoryInterface $logRepository
    ) {}

    /**
     * Display the settings form page.
     */
    public function index(Request $request): Response
    {
        Gate::authorize('viewAny', \App\Models\QzCertificate::class);

        $cert = $this->certificateService->getActiveCertificate();
        $status = $this->certificateService->getCertificateStatus($cert);
        $isOpenSslAvailable = $this->certificateService->isOpenSslAvailable();
        
        $recentLogs = $this->logRepository->getRecent(10);
        $paginatedLogs = $this->logRepository->getPaginated(10);

        return Inertia::render('Settings/QzTray', [
            'certificate' => $cert ? [
                'id' => $cert->id,
                'name' => $cert->name,
                'public_certificate' => $cert->public_certificate,
                'fingerprint' => $cert->fingerprint,
                'algorithm' => $cert->algorithm,
                'created_at' => $cert->created_at?->toIso8601String(),
                'expires_at' => $cert->expires_at?->toIso8601String(),
                'last_used_at' => $cert->last_used_at?->toIso8601String(),
            ] : null,
            'status' => $status,
            'isOpenSslAvailable' => $isOpenSslAvailable,
            'recentLogs' => $recentLogs->map(fn($log) => [
                'id' => $log->id,
                'user_name' => $log->user_name ?? 'System',
                'ip_address' => $log->ip_address,
                'action' => $log->action,
                'result' => $log->result,
                'details' => $log->details,
                'created_at' => $log->created_at?->toIso8601String(),
            ]),
            'paginatedLogs' => $paginatedLogs,
            'config' => [
                'key_size' => config('qztray.key_size'),
                'validity_days' => config('qztray.validity_days'),
                'signature_algorithm' => config('qztray.signature_algorithm'),
                'dn' => config('qztray.dn'),
            ],
        ]);
    }

    /**
     * Generate a new certificate.
     */
    public function generate(GenerateCertificateRequest $request): RedirectResponse
    {
        Gate::authorize('create', \App\Models\QzCertificate::class);

        try {
            $cert = $this->certificateService->generate(
                $request->input('name'),
                $request->only(['country', 'state', 'locality', 'organization', 'organizational_unit', 'common_name', 'email']),
                $request->user()?->id
            );

            event(new CertificateGenerated($cert, $request->user(), $request->ip()));

            return redirect()->back()->with('success', 'QZ Tray certificate generated successfully.');
        } catch (\Throwable $e) {
            return redirect()->back()->with('error', 'Generation failed: ' . $e->getMessage());
        }
    }

    /**
     * Regenerate the certificate.
     */
    public function regenerate(GenerateCertificateRequest $request): RedirectResponse
    {
        Gate::authorize('create', \App\Models\QzCertificate::class);

        try {
            $oldCert = $this->certificateService->getActiveCertificate();

            // Generate new certificate
            $newCert = $this->certificateService->generate(
                $request->input('name'),
                $request->only(['country', 'state', 'locality', 'organization', 'organizational_unit', 'common_name', 'email']),
                $request->user()?->id
            );

            // Delete old key and certificate entries
            if ($oldCert) {
                $this->certificateService->delete($oldCert);
            }

            event(new CertificateRegenerated($newCert, $request->user(), $request->ip()));

            return redirect()->back()->with('success', 'QZ Tray certificate regenerated successfully. Previous signatures are now invalidated.');
        } catch (\Throwable $e) {
            return redirect()->back()->with('error', 'Regeneration failed: ' . $e->getMessage());
        }
    }

    /**
     * Delete the active certificate.
     */
    public function destroy(Request $request): RedirectResponse
    {
        Gate::authorize('delete', \App\Models\QzCertificate::class);

        $cert = $this->certificateService->getActiveCertificate();

        if (!$cert) {
            return redirect()->back()->with('error', 'No active certificate to delete.');
        }

        try {
            $certName = $cert->name;
            $this->certificateService->delete($cert);

            event(new CertificateDeleted($certName, $request->user(), $request->ip()));

            return redirect()->back()->with('success', 'QZ Tray certificate deleted successfully.');
        } catch (\Throwable $e) {
            return redirect()->back()->with('error', 'Deletion failed: ' . $e->getMessage());
        }
    }

    /**
     * Download the public certificate.
     */
    public function download(Request $request)
    {
        Gate::authorize('viewAny', \App\Models\QzCertificate::class);

        $cert = $this->certificateService->getActiveCertificate();

        if (!$cert || !$cert->public_certificate) {
            abort(404, 'No active certificate found.');
        }

        $filename = str_replace(' ', '_', strtolower($cert->name)) . '_public.pem';

        return response($cert->public_certificate, 200, [
            'Content-Type' => 'application/x-x509-ca-cert',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ]);
    }

    /**
     * Sign a print request payload.
     */
    public function sign(SignPayloadRequest $request): JsonResponse
    {
        $payload = $request->input('payload');

        try {
            $signature = $this->signingService->sign($payload);

            event(new PayloadSigned($payload, $request->user(), $request->ip()));

            return response()->json([
                'success' => true,
                'signature' => $signature,
            ]);
        } catch (\Throwable $e) {
            event(new SigningFailed($e->getMessage(), $request->user(), $request->ip()));

            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ], 422);
        }
    }
}
