<?php

namespace App\Domains\Ticket\Services;

use App\Domains\Tenant\Models\Tenant;
use App\Domains\Ticket\Models\Ticket;
use Barryvdh\DomPDF\Facade\Pdf;
use Barryvdh\DomPDF\PDF as DomPdf;
use Endroid\QrCode\ErrorCorrectionLevel;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\Writer\PngWriter;
use Illuminate\Http\Response;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Storage;
use Throwable;

class TicketPdfService
{
    /**
     * @param  Collection<int, Ticket>  $tickets
     */
    public function download(Tenant $tenant, Collection $tickets): Response
    {
        return $this->pdf($tenant, $tickets)->download($this->filename($tickets));
    }

    /**
     * @param  Collection<int, Ticket>  $tickets
     */
    public function contents(Tenant $tenant, Collection $tickets): string
    {
        return $this->pdf($tenant, $tickets)->output();
    }

    /**
     * @param  Collection<int, Ticket>  $tickets
     */
    public function filename(Collection $tickets): string
    {
        return 'tickets_'.$tickets->pluck('id')->implode('_').'.pdf';
    }

    /**
     * @param  Collection<int, Ticket>  $tickets
     */
    private function pdf(Tenant $tenant, Collection $tickets): DomPdf
    {
        $tenant->loadMissing('headerLogo');
        $primaryColor = $this->color($tenant->primary_color, '#009933');
        $headerBackgroundColor = $this->color($tenant->header_bg_color, $primaryColor);

        return Pdf::loadView('pdf.tickets', [
            'tenant' => $tenant,
            'tickets' => $tickets,
            'logoDataUri' => $this->logoDataUri($tenant),
            'primaryColor' => $primaryColor,
            'headerBackgroundColor' => $headerBackgroundColor,
            'headerTextColor' => $this->contrastingTextColor($headerBackgroundColor),
            'qrCodes' => $tickets->mapWithKeys(
                fn (Ticket $ticket): array => [$ticket->id => $this->qrCodeDataUri($ticket->ticket)]
            ),
        ])->setPaper('a4');
    }

    private function qrCodeDataUri(string $value): string
    {
        $qrCode = new QrCode(
            data: $value,
            errorCorrectionLevel: ErrorCorrectionLevel::Medium,
            size: 700,
            margin: 10,
        );

        return (new PngWriter)->write($qrCode)->getDataUri();
    }

    private function logoDataUri(Tenant $tenant): ?string
    {
        $logo = $tenant->headerLogo;
        if ($logo === null) {
            return null;
        }

        try {
            $contents = Storage::disk('s3')->get($logo->path);
        } catch (Throwable) {
            return null;
        }

        return 'data:'.($logo->mime_type ?: 'image/png').';base64,'.base64_encode($contents);
    }

    private function color(?string $color, string $fallback): string
    {
        return is_string($color) && preg_match('/^#[0-9A-Fa-f]{6}$/', $color)
            ? $color
            : $fallback;
    }

    private function contrastingTextColor(string $backgroundColor): string
    {
        $red = hexdec(substr($backgroundColor, 1, 2));
        $green = hexdec(substr($backgroundColor, 3, 2));
        $blue = hexdec(substr($backgroundColor, 5, 2));
        $luminance = ($red * 299 + $green * 587 + $blue * 114) / 1000;

        return $luminance > 160 ? '#17211b' : '#ffffff';
    }
}
