<?php

namespace Maestro\Core\Http\Controllers;

use Maestro\Core\DataTables\DataTableRegistry;
use Illuminate\Routing\Controller;
use Maestro\Core\Models\DataTableExport;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
use function activity;

/**
 * Export list (for header notifications), status and download: GET /api/datatables/exports, GET /api/datatables/exports/{id}, GET /api/datatables/exports/{id}/download.
 * Access: ownership (export.user_id === auth id) + view permission for export.resource_key.
 */
class DataTableExportController extends Controller
{
    public function __construct(
        private readonly DataTableRegistry $registry
    ) {}

    /**
     * Clear all ready exports for the current user: delete files and mark them as completed.
     * Used by the header "clear all" button.
     */
    public function clearReady(Request $request): JsonResponse
    {
        $userId = $request->user()?->id;
        if (! $userId) {
            return response()->json(['message' => 'Unauthenticated.'], 401);
        }

        $exports = DataTableExport::query()
            ->where('user_id', $userId)
            ->where('status', DataTableExport::STATUS_READY)
            ->whereNotNull('file_path')
            ->get();

        $disk = Storage::disk('exports');
        $cleared = 0;
        $filesDeleted = 0;

        foreach ($exports as $export) {
            $cleared++;
            if ($export->file_path && $disk->exists($export->file_path)) {
                $disk->delete($export->file_path);
                $filesDeleted++;
            }

            $export->update([
                'status' => DataTableExport::STATUS_COMPLETED,
            ]);
        }

        return response()->json([
            'cleared' => $cleared,
            'filesDeleted' => $filesDeleted,
        ]);
    }

    /**
     * List current user's exports that are pending, processing, or completed with download available.
     * Used by the frontend header to show "download ready" notifications.
     *
     * @return JsonResponse { data: [{ id, resourceKey, status, downloadUrl?, errorMessage? }] }
     */
    public function index(Request $request): JsonResponse
    {
        $userId = $request->user()?->id;
        if (! $userId) {
            return response()->json(['data' => []], 200);
        }

        // Only include exports that are still ready to download:
        // - owned by the current user
        // - status = ready
        // - file_path is set
        // - download_expires_at is in the future
        $exports = DataTableExport::query()
            ->where('user_id', $userId)
            ->where('status', DataTableExport::STATUS_READY)
            ->whereNotNull('file_path')
            ->where('download_expires_at', '>', now())
            ->orderByDesc('created_at')
            ->limit(20)
            ->get();

        $data = [];
        foreach ($exports as $export) {
            try {
                $resource = $this->registry->resolve($export->resource_key);
                $resource->authorize($request);
            } catch (\Illuminate\Auth\Access\AuthorizationException) {
                continue;
            }

            $item = [
                'id' => $export->id,
                'resourceKey' => $export->resource_key,
                'status' => $export->status,
                'createdAt' => $export->created_at?->toIso8601String(),
            ];

            $resourceLabel = trans('datatable.resources.' . $export->resource_key);
            if ($resourceLabel === 'datatable.resources.' . $export->resource_key) {
                $resourceLabel = $export->resource_key;
            }
            $item['resourceLabel'] = $resourceLabel;

            if ($export->isDownloadAvailable()) {
                // Plain URL to the download endpoint; auth + ownership + permission still enforced in controller.
                $item['downloadUrl'] = url("/api/datatables/exports/{$export->id}/download");
            }

            if ($export->isFailed() && $export->error_message) {
                $item['errorMessage'] = $export->error_message;
            }

            $data[] = $item;
        }

        return response()->json(['data' => $data]);
    }

    /**
     * Return export status. When completed, include a download URL.
     */
    public function show(Request $request, string $id): JsonResponse
    {
        $export = DataTableExport::find($id);
        if (! $export) {
            return response()->json(['message' => 'Export not found.'], 404);
        }

        if ($export->user_id !== $request->user()?->id) {
            return response()->json(['message' => 'Unauthorized.'], 403);
        }

        $resource = $this->registry->resolve($export->resource_key);
        try {
            $resource->authorize($request);
        } catch (\Illuminate\Auth\Access\AuthorizationException) {
            return response()->json(['message' => 'You no longer have permission to access this export.'], 403);
        }

        $resourceLabel = trans('datatable.resources.' . $export->resource_key);
        if ($resourceLabel === 'datatable.resources.' . $export->resource_key) {
            $resourceLabel = $export->resource_key;
        }

        $payload = [
            'id' => $export->id,
            'status' => $export->status,
            'resourceKey' => $export->resource_key,
            'resourceLabel' => $resourceLabel,
        ];

        if ($export->isDownloadAvailable()) {
            $payload['downloadUrl'] = url("/api/datatables/exports/{$export->id}/download");
        }

        if ($export->isFailed() && $export->error_message) {
            $payload['errorMessage'] = $export->error_message;
        }

        return response()->json($payload);
    }

    /**
     * Stream the export file. Requires auth, ownership, and view permission.
     */
    public function download(Request $request, string $id): StreamedResponse|JsonResponse|BinaryFileResponse
    {
        $export = DataTableExport::find($id);
        if (! $export) {
            return response()->json(['message' => 'Export not found.'], 404);
        }

        if ($export->user_id !== $request->user()?->id) {
            return response()->json(['message' => 'Unauthorized.'], 403);
        }

        $resource = $this->registry->resolve($export->resource_key);
        try {
            $resource->authorize($request);
        } catch (\Illuminate\Auth\Access\AuthorizationException) {
            return response()->json(['message' => 'You do not have permission to download this export.'], 403);
        }

        if (! $export->isDownloadAvailable()) {
            return response()->json([
                'message' => $export->status === DataTableExport::STATUS_READY
                    ? 'Downloadlink is verlopen.'
                    : 'Export is niet (meer) beschikbaar voor download.',
            ], 410);
        }

        $path = $export->file_path;
        $disk = Storage::disk('exports');
        if (! $disk->exists($path)) {
            return response()->json(['message' => 'Export file no longer available.'], 410);
        }

        $filename = basename($path);
        $absolutePath = $disk->path($path);

        // After the response is sent, delete the file and mark export as completed and no longer downloadable (one-time download).
        // We keep file_path and download_expires_at for full history; isDownloadAvailable() checks status === READY.
        app()->terminating(function () use ($export, $path, $disk, $request): void {
            if ($disk->exists($path)) {
                $disk->delete($path);
            }
            $export->update([
                'status' => DataTableExport::STATUS_COMPLETED,
            ]);

            if ($request->user()) {
                activity('data_export')
                    ->causedBy($request->user())
                    ->event('export')
                    ->withProperties([
                        'resource_key' => $export->resource_key,
                        'export_id' => $export->id,
                        'status' => DataTableExport::STATUS_COMPLETED,
                    ])
                    ->log('Data export to CSV downloaded for: ' . $export->resource_key);
            }
        });

        return response()->download($absolutePath, $filename, [
            'Content-Type' => 'text/csv; charset=UTF-8',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
            'Cache-Control' => 'no-cache, no-store, must-revalidate',
            'Pragma' => 'no-cache',
            'Expires' => '0',
        ]);
    }
}
