<?php

namespace App\Http\Controllers\Api\Tenant;

use App\Http\Controllers\Controller;
use App\Http\Requests\Tenant\DataExportStoreRequest;
use App\Jobs\GenerateDataExport;
use App\Models\DataExport;
use App\Models\Event;
use App\Models\Tenant;
use App\Support\ApiError;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

class DataExportController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $tenant = $this->resolveTenant($request);

        $exports = DataExport::query()
            ->with('event')
            ->where('tenant_id', $tenant->id)
            ->whereIn('scope', ['tenant', 'event'])
            ->latest()
            ->limit(10)
            ->get()
            ->map(fn (DataExport $export) => [
                'id' => $export->id,
                'scope' => $export->scope?->value ?? $export->scope,
                'status' => $export->status,
                'include_media' => (bool) $export->include_media,
                'size_bytes' => $export->size_bytes,
                'created_at' => optional($export->created_at)->toIso8601String(),
                'expires_at' => optional($export->expires_at)->toIso8601String(),
                'download_url' => $export->isReady() && ! $export->hasExpired()
                    ? route('api.v1.tenant.exports.download', $export)
                    : null,
                'error_message' => $export->error_message,
                'event' => $export->event ? [
                    'id' => $export->event->id,
                    'slug' => $export->event->slug,
                    'name' => $export->event->name,
                ] : null,
            ]);

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

    public function store(DataExportStoreRequest $request): JsonResponse
    {
        $tenant = $this->resolveTenant($request);
        $user = $request->user();

        if (! $user) {
            return ApiError::response(
                'export_user_missing',
                'Export user missing',
                'Unable to determine the requesting user.',
                Response::HTTP_UNAUTHORIZED
            );
        }

        $payload = $request->validated();
        $scope = $payload['scope'];
        $event = null;

        if ($scope === 'event') {
            $event = Event::query()
                ->where('tenant_id', $tenant->id)
                ->find($payload['event_id']);

            if (! $event) {
                return ApiError::response(
                    'export_event_missing',
                    'Event not found',
                    'The selected event does not exist for this tenant.',
                    Response::HTTP_NOT_FOUND
                );
            }
        }

        $hasInProgress = DataExport::query()
            ->where('tenant_id', $tenant->id)
            ->whereIn('status', [DataExport::STATUS_PENDING, DataExport::STATUS_PROCESSING])
            ->exists();

        if ($hasInProgress) {
            return ApiError::response(
                'export_in_progress',
                'Export already in progress',
                'Please wait for the current export to finish before requesting another.',
                Response::HTTP_CONFLICT
            );
        }

        $export = DataExport::query()->create([
            'user_id' => $user->id,
            'tenant_id' => $tenant->id,
            'event_id' => $event?->id,
            'scope' => $scope,
            'include_media' => (bool) ($payload['include_media'] ?? false),
            'status' => DataExport::STATUS_PENDING,
        ]);

        GenerateDataExport::dispatch($export->id);

        return response()->json([
            'message' => 'Export started.',
            'data' => [
                'id' => $export->id,
                'scope' => $export->scope?->value ?? $export->scope,
                'status' => $export->status,
                'include_media' => (bool) $export->include_media,
                'created_at' => optional($export->created_at)->toIso8601String(),
            ],
        ], Response::HTTP_ACCEPTED);
    }

    public function download(Request $request, DataExport $export): StreamedResponse|JsonResponse
    {
        $tenant = $this->resolveTenant($request);

        if ((int) $export->tenant_id !== (int) $tenant->id) {
            return ApiError::response(
                'export_not_found',
                'Export not found',
                'The requested export is not available for this tenant.',
                Response::HTTP_NOT_FOUND
            );
        }

        if (! $export->isReady() || $export->hasExpired() || ! $export->path) {
            return ApiError::response(
                'export_not_ready',
                'Export not ready',
                'The export is not ready or has expired.',
                Response::HTTP_BAD_REQUEST
            );
        }

        $disk = 'local';

        if (! Storage::disk($disk)->exists($export->path)) {
            return ApiError::response(
                'export_missing',
                'Export not found',
                'The export archive could not be located.',
                Response::HTTP_NOT_FOUND
            );
        }

        return Storage::disk($disk)->download(
            $export->path,
            sprintf('fotospiel-data-export-%s.zip', $export->created_at?->format('Ymd') ?? now()->format('Ymd')),
            [
                'Cache-Control' => 'private, no-store',
            ]
        );
    }

    private function resolveTenant(Request $request): Tenant
    {
        $tenant = $request->attributes->get('tenant');

        if ($tenant instanceof Tenant) {
            return $tenant;
        }

        $tenantId = $request->attributes->get('tenant_id')
            ?? $request->attributes->get('current_tenant_id')
            ?? $request->user()?->tenant_id;

        if ($tenantId) {
            $tenant = Tenant::query()->find($tenantId);
            if ($tenant) {
                $request->attributes->set('tenant', $tenant);

                return $tenant;
            }
        }

        abort(401, 'Tenant context missing.');
    }
}
