<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\GdprRequest;
use App\Models\User;
use App\Services\Gdpr\GdprAuditService;
use App\Services\Gdpr\GdprExportService;
use App\Services\Gdpr\GdprNotificationService;
use App\Services\Gdpr\GdprRetentionService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\StreamedResponse;

class PrivacyCenterController extends BasePageController
{
    public function index(GdprRetentionService $retentionService): View
    {
        /** @var User $user */
        $user = Auth::user();

        $requests = GdprRequest::query()
            ->where('user_id', $user->id)
            ->orderByDesc('created_at')
            ->paginate(10);

        $this->viewData = array_merge($this->viewData, [
            'user' => $user,
            'gdprRequests' => $requests,
            'retentionPolicy' => $retentionService->policy(),
            'meta_title' => 'Privacy Center',
            'meta_keywords' => 'privacy,gdpr,data export,erasure',
            'meta_description' => 'Manage your privacy and GDPR data requests',
        ]);

        return view('privacy-center.index', $this->viewData);
    }

    public function requestExport(Request $request, GdprExportService $exportService, GdprAuditService $auditService): RedirectResponse
    {
        /** @var User $user */
        $user = Auth::user();

        $validated = $request->validate([
            'notes' => ['nullable', 'string', 'max:2000'],
        ]);

        // Block regeneration while a previously generated export is still downloadable.
        // This bounds the heavy, synchronous export work and avoids accumulating PII files.
        $activeExport = GdprRequest::query()
            ->where('user_id', $user->id)
            ->where('type', GdprRequest::TYPE_EXPORT)
            ->where('status', GdprRequest::STATUS_COMPLETED)
            ->whereNotNull('export_path')
            ->where(function ($query): void {
                $query->whereNull('export_expires_at')
                    ->orWhere('export_expires_at', '>', now());
            })
            ->exists();

        if ($activeExport) {
            return redirect()
                ->route('privacy-center.index')
                ->with('error', 'You already have an active data export available for download. Please use or wait for it to expire before requesting a new one.');
        }

        $gdprRequest = GdprRequest::create([
            'user_id' => $user->id,
            'requester_username' => $user->username,
            'requester_email' => $user->email,
            'type' => GdprRequest::TYPE_EXPORT,
            'status' => GdprRequest::STATUS_PROCESSING,
            'request_payload' => [
                'requested_by' => 'self_service',
                'ip_recorded' => (bool) config('nntmux_settings.store_user_ip'),
            ],
            'notes' => $validated['notes'] ?? null,
        ]);

        $auditService->record(
            event: 'request_submitted',
            description: 'Self-service GDPR export request submitted.',
            subject: $user,
            actor: $user,
            request: $gdprRequest,
            metadata: ['type' => GdprRequest::TYPE_EXPORT]
        );

        $exportService->generate($user, $gdprRequest, $user);

        return redirect()
            ->route('privacy-center.index')
            ->with('success', 'Your data export has been generated and is available for 7 days.');
    }

    public function requestErasure(Request $request, GdprAuditService $auditService, GdprNotificationService $notificationService): RedirectResponse
    {
        /** @var User $user */
        $user = Auth::user();

        if ($user->hasRole('Admin')) {
            return redirect()
                ->route('privacy-center.index')
                ->with('error', 'Admin accounts cannot submit self-service erasure requests.');
        }

        $validated = $request->validate([
            'confirmation' => ['required', 'string', 'in:ERASE'],
            'notes' => ['nullable', 'string', 'max:2000'],
        ]);

        $openRequestExists = GdprRequest::query()
            ->where('user_id', $user->id)
            ->where('type', GdprRequest::TYPE_ERASURE)
            ->open()
            ->exists();

        if ($openRequestExists) {
            return redirect()
                ->route('privacy-center.index')
                ->with('error', 'You already have an open account erasure request.');
        }

        $gdprRequest = GdprRequest::create([
            'user_id' => $user->id,
            'requester_username' => $user->username,
            'requester_email' => $user->email,
            'type' => GdprRequest::TYPE_ERASURE,
            'status' => GdprRequest::STATUS_PENDING,
            'request_payload' => [
                'requested_by' => 'self_service',
                'confirmation' => $validated['confirmation'],
            ],
            'notes' => $validated['notes'] ?? null,
        ]);

        $auditService->record(
            event: 'request_submitted',
            description: 'Self-service GDPR erasure request submitted.',
            subject: $user,
            actor: $user,
            request: $gdprRequest,
            metadata: ['type' => GdprRequest::TYPE_ERASURE]
        );

        $notificationService->requestSubmitted($gdprRequest);

        return redirect()
            ->route('privacy-center.index')
            ->with('success', 'Your account erasure request has been submitted for administrator review.');
    }

    public function downloadExport(GdprRequest $gdprRequest): StreamedResponse|RedirectResponse
    {
        /** @var User $user */
        $user = Auth::user();

        if ((int) $gdprRequest->user_id !== (int) $user->id || ! $gdprRequest->isDownloadableExport()) {
            return redirect()->route('privacy-center.index')->with('error', 'The requested export is not available.');
        }

        $disk = $gdprRequest->export_disk ?: 'local';
        if (! Storage::disk($disk)->exists($gdprRequest->export_path)) {
            return redirect()->route('privacy-center.index')->with('error', 'The requested export file has expired or is missing.');
        }

        return Storage::disk($disk)->download($gdprRequest->export_path, 'gdpr-export-'.$user->id.'.json');
    }
}
