<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\NovaCards;

use App\Events\NovaCards\NovaCardBackgroundUploaded;
use App\Events\NovaCards\NovaCardPublished;
use App\Http\Controllers\Controller;
use App\Http\Requests\NovaCards\SaveNovaCardDraftRequest;
use App\Http\Requests\NovaCards\StoreNovaCardDraftRequest;
use App\Http\Requests\NovaCards\UploadNovaCardBackgroundRequest;
use App\Models\NovaCard;
use App\Services\NovaCards\NovaCardBackgroundService;
use App\Services\NovaCards\NovaCardDraftService;
use App\Services\NovaCards\NovaCardPresenter;
use App\Services\NovaCards\NovaCardPublishService;
use App\Services\NovaCards\NovaCardRenderService;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class NovaCardDraftController extends Controller
{
    public function __construct(
        private readonly NovaCardDraftService $drafts,
        private readonly NovaCardBackgroundService $backgrounds,
        private readonly NovaCardRenderService $renders,
        private readonly NovaCardPublishService $publishes,
        private readonly NovaCardPresenter $presenter,
    ) {
    }

    public function store(StoreNovaCardDraftRequest $request): JsonResponse
    {
        $card = $this->drafts->createDraft($request->user(), $request->validated());

        return response()->json([
            'data' => $this->presenter->card($card, true, $request->user()),
        ], Response::HTTP_CREATED);
    }

    public function show(Request $request, int $id): JsonResponse
    {
        $card = $this->editableCard($request, $id);

        return response()->json([
            'data' => $this->presenter->card($card, true, $request->user()),
        ]);
    }

    public function update(SaveNovaCardDraftRequest $request, int $id): JsonResponse
    {
        $card = $this->editableCard($request, $id);
        $card = $this->drafts->autosave($card, $request->validated());

        return response()->json([
            'data' => $this->presenter->card($card, true, $request->user()),
        ]);
    }

    public function autosave(SaveNovaCardDraftRequest $request, int $id): JsonResponse
    {
        $card = $this->editableCard($request, $id);
        $card = $this->drafts->autosave($card, $request->validated());

        return response()->json([
            'data' => $this->presenter->card($card, true, $request->user()),
            'meta' => [
                'saved_at' => now()->toISOString(),
            ],
        ]);
    }

    public function background(UploadNovaCardBackgroundRequest $request, int $id): JsonResponse
    {
        $card = $this->editableCard($request, $id);
        $background = $this->backgrounds->storeUploadedBackground($request->user(), $request->file('background'));

        $card = $this->drafts->autosave($card, [
            'background_type' => 'upload',
            'background_image_id' => $background->id,
            'project_json' => [
                'background' => [
                    'type' => 'upload',
                    'background_image_id' => $background->id,
                ],
            ],
        ]);

        event(new NovaCardBackgroundUploaded($card, $background));

        return response()->json([
            'data' => $this->presenter->card($card, true, $request->user()),
            'background' => [
                'id' => (int) $background->id,
                'processed_url' => $background->processedUrl(),
                'width' => (int) $background->width,
                'height' => (int) $background->height,
            ],
        ], Response::HTTP_CREATED);
    }

    public function render(Request $request, int $id): JsonResponse
    {
        $card = $this->editableCard($request, $id);
        $result = $this->renders->render($card->loadMissing('backgroundImage'));

        return response()->json([
            'data' => $this->presenter->card($card->fresh()->loadMissing(['user.profile', 'category', 'template', 'backgroundImage', 'tags']), true, $request->user()),
            'render' => $result,
        ]);
    }

    public function publish(SaveNovaCardDraftRequest $request, int $id): JsonResponse
    {
        $card = $this->editableCard($request, $id);
        $validated = $request->validated();

        if ($validated !== []) {
            $card = $this->drafts->autosave($card, $validated);
        }

        if (trim((string) $card->title) === '' || trim((string) $card->quote_text) === '') {
            return response()->json([
                'message' => 'Title and quote text are required before publishing.',
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $publishMode = (string) ($validated['publish_mode'] ?? 'now');

        if ($publishMode === 'schedule') {
            if (empty($validated['scheduled_for'])) {
                return response()->json([
                    'message' => 'Choose a date and time for scheduled publishing.',
                ], Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            try {
                $card = $this->publishes->schedule(
                    $card->loadMissing('backgroundImage'),
                    Carbon::parse((string) $validated['scheduled_for']),
                    isset($validated['scheduling_timezone']) ? (string) $validated['scheduling_timezone'] : null,
                );
            } catch (\InvalidArgumentException $exception) {
                return response()->json([
                    'message' => $exception->getMessage(),
                ], Response::HTTP_UNPROCESSABLE_ENTITY);
            }

            return response()->json([
                'data' => $this->presenter->card($card, true, $request->user()),
            ]);
        }

        $card = $this->publishes->publishNow($card->loadMissing('backgroundImage'));
        event(new NovaCardPublished($card));

        return response()->json([
            'data' => $this->presenter->card($card, true, $request->user()),
        ]);
    }

    public function destroy(Request $request, int $id): JsonResponse
    {
        $card = $this->editableCard($request, $id);

        if ($card->status === NovaCard::STATUS_PUBLISHED && in_array($card->visibility, [NovaCard::VISIBILITY_PUBLIC, NovaCard::VISIBILITY_UNLISTED], true)) {
            return response()->json([
                'message' => 'Published cards cannot be deleted from the draft API.',
            ], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        $card->delete();

        return response()->json([
            'ok' => true,
        ]);
    }

    private function editableCard(Request $request, int $id): NovaCard
    {
        return NovaCard::query()
            ->with(['user.profile', 'category', 'template', 'backgroundImage', 'tags'])
            ->where('user_id', $request->user()->id)
            ->findOrFail($id);
    }
}
