<?php

declare(strict_types=1);

namespace App\Services\NovaCards;

use App\Jobs\NovaCards\GenerateNovaCardExportJob;
use App\Models\NovaCard;
use App\Models\NovaCardExport;
use App\Models\User;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Storage;

/**
 * Handles export request creation, status checking, and file resolution.
 * Actual rendering is delegated to GenerateNovaCardExportJob (queued).
 */
class NovaCardExportService
{
    /** How long (in minutes) a generated export file is available. */
    private const EXPORT_TTL_MINUTES = 60;

    /** Allowed export types and their canvas dimensions. */
    public const EXPORT_SPECS = [
        NovaCardExport::TYPE_PREVIEW  => ['width' => 1080, 'height' => 1080, 'format' => 'webp'],
        NovaCardExport::TYPE_HIRES    => ['width' => 2160, 'height' => 2160, 'format' => 'webp'],
        NovaCardExport::TYPE_SQUARE   => ['width' => 1080, 'height' => 1080, 'format' => 'webp'],
        NovaCardExport::TYPE_STORY    => ['width' => 1080, 'height' => 1920, 'format' => 'webp'],
        NovaCardExport::TYPE_WALLPAPER => ['width' => 2560, 'height' => 1440, 'format' => 'webp'],
        NovaCardExport::TYPE_OG       => ['width' => 1200, 'height' => 630, 'format' => 'jpg'],
    ];

    public function requestExport(User $user, NovaCard $card, string $exportType, array $options = []): NovaCardExport
    {
        if (! $card->allow_export && ! $card->isOwnedBy($user)) {
            abort(403, 'This card does not allow exports.');
        }

        $spec = self::EXPORT_SPECS[$exportType] ?? self::EXPORT_SPECS[NovaCardExport::TYPE_PREVIEW];

        // Reuse a recent pending/ready non-expired export for the same type.
        $existing = NovaCardExport::query()
            ->where('card_id', $card->id)
            ->where('user_id', $user->id)
            ->where('export_type', $exportType)
            ->whereIn('status', [NovaCardExport::STATUS_READY, NovaCardExport::STATUS_PENDING, NovaCardExport::STATUS_PROCESSING])
            ->where('expires_at', '>', now())
            ->orderByDesc('created_at')
            ->first();

        if ($existing !== null) {
            return $existing;
        }

        $export = NovaCardExport::query()->create([
            'card_id' => $card->id,
            'user_id' => $user->id,
            'export_type' => $exportType,
            'status' => NovaCardExport::STATUS_PENDING,
            'width' => $spec['width'],
            'height' => $spec['height'],
            'format' => $spec['format'],
            'options_json' => $options,
            'expires_at' => now()->addMinutes(self::EXPORT_TTL_MINUTES),
        ]);

        GenerateNovaCardExportJob::dispatch($export->id)
            ->onQueue((string) config('nova_cards.render.queue', 'default'));

        return $export->refresh();
    }

    public function getStatus(NovaCardExport $export): array
    {
        return [
            'id' => (int) $export->id,
            'export_type' => (string) $export->export_type,
            'status' => (string) $export->status,
            'output_url' => $export->isReady() && ! $export->isExpired() ? $export->outputUrl() : null,
            'width' => $export->width,
            'height' => $export->height,
            'format' => (string) $export->format,
            'ready_at' => optional($export->ready_at)?->toISOString(),
            'expires_at' => optional($export->expires_at)?->toISOString(),
        ];
    }

    public function cleanupExpired(): int
    {
        $exports = NovaCardExport::query()
            ->where('expires_at', '<', now())
            ->whereNotNull('output_path')
            ->get();

        $count = 0;
        foreach ($exports as $export) {
            $disk = Storage::disk((string) config('nova_cards.storage.public_disk', 'public'));
            if ($export->output_path && $disk->exists($export->output_path)) {
                $disk->delete($export->output_path);
            }
            $export->delete();
            $count++;
        }

        return $count;
    }
}
