<?php

namespace App\Domains\Ticket\Listeners;

use App\Domains\Catalog\Models\CatalogItem;
use App\Domains\Notification\Events\TicketsAvailable;
use App\Domains\Purchase\Events\PurchasePaid;
use App\Domains\Ticket\Exceptions\TicketGenerationException;
use App\Domains\Ticket\Services\TicketGeneratorService;

class GenerateTicketsForPaidPurchase
{
    public function __construct(
        private readonly TicketGeneratorService $ticketGenerator,
    ) {}

    public function handle(PurchasePaid $event): void
    {
        $purchase = $event->purchase
            ->newQuery()
            ->with(['user', 'items'])
            ->findOrFail($event->purchase->getKey());
        $user = $purchase->user;
        $ticketIds = [];

        foreach ($purchase->items as $purchaseItem) {
            $catalogItem = CatalogItem::query()
                ->where('tenant_code', $purchase->tenant_codigo)
                ->find($purchaseItem->source_catalog_item_id);

            if ($catalogItem === null) {
                throw TicketGenerationException::catalogItemNotFound($purchaseItem);
            }

            if (! $this->requiresTickets($catalogItem)) {
                continue;
            }

            if ($user === null) {
                throw TicketGenerationException::purchaseWithoutUser($purchase);
            }

            $generatedTickets = $this->ticketGenerator->generate(
                $catalogItem,
                $user,
                $purchaseItem->cantidad,
                $purchaseItem->source_variant_id,
                $purchase->getKey(),
            );

            array_push($ticketIds, ...$generatedTickets->pluck('id')->all());
        }

        if ($ticketIds !== []) {
            TicketsAvailable::dispatch($purchase, $ticketIds);
        }
    }

    private function requiresTickets(CatalogItem $catalogItem): bool
    {
        if (! $catalogItem->isBundle()) {
            return $catalogItem->has_tickets;
        }

        return $catalogItem->bundleComponents()
            ->whereHas(
                'catalogItem',
                fn ($query) => $query->where('has_tickets', true),
            )
            ->exists();
    }
}
