<?php

namespace Modules\User\Services;

use BaconQrCode\Renderer\Image\SvgImageBackEnd;
use BaconQrCode\Renderer\ImageRenderer;
use BaconQrCode\Renderer\RendererStyle\RendererStyle;
use BaconQrCode\Writer;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\View;
use Modules\Auth\Entities\User;
use Spatie\Browsershot\Browsershot;

class MemberDigitalCardService
{
    public const CARD_WIDTH = 840;

    public const CARD_HEIGHT = 540;

    public function renderPng(User $user, string $side): string
    {
        $view = $side === 'belakang'
            ? 'user::digital-card.back'
            : 'user::digital-card.front';

        $html = View::make($view, $this->prepareViewData($user))->render();

        return $this->makeBrowsershot($html)->screenshot();
    }

    /**
     * @return array<string, mixed>
     */
    protected function prepareViewData(User $user): array
    {
        $user = app(PublicMemberProfileService::class)->loadVerifiableRelations($user);
        $user->ensurePublicProfileToken();

        $currentEmployment = $user->employments->firstWhere('is_current', true)
            ?? $user->employments->first();

        $logoPath = config('user.digital_card_logo_path');
        $profileUrl = rtrim(config('user.frontend_url'), '/').'/v/'.$user->public_profile_token;

        return [
            'memberNumber' => $this->displayCardValue($user->member_number),
            'memberName' => $user->name ?: '-',
            'memberType' => $this->displayCardValue($user->member_type),
            'companyName' => $this->displayCardValue($currentEmployment?->company_name),
            'avatarDataUri' => $this->resolveStorageDataUri($user->image_url),
            'avatarInitials' => $this->avatarInitials($user->name),
            'logoDataUri' => $this->resolveFileDataUri($logoPath),
            'profileUrl' => $profileUrl,
            'qrDataUri' => $this->generateQrDataUri($profileUrl),
        ];
    }

    protected function makeBrowsershot(string $html): Browsershot
    {
        $browsershot = Browsershot::html($html)
            ->setNodeModulePath(config('browsershot.node_module_path'))
            ->timeout(config('browsershot.timeout'))
            ->windowSize(self::CARD_WIDTH, self::CARD_HEIGHT)
            ->deviceScaleFactor(2)
            ->showBackground();

        if ($nodeBinary = config('browsershot.node_binary')) {
            $browsershot->setNodeBinary($nodeBinary);
        }

        if ($npmBinary = config('browsershot.npm_binary')) {
            $browsershot->setNpmBinary($npmBinary);
        }

        if ($chromePath = config('browsershot.chrome_path')) {
            $browsershot->setChromePath($chromePath);
        }

        if (config('browsershot.no_sandbox')) {
            $browsershot->noSandbox();
        }

        return $browsershot;
    }

    protected function generateQrDataUri(string $content): string
    {
        $renderer = new ImageRenderer(
            new RendererStyle(220, 1),
            new SvgImageBackEnd
        );
        $writer = new Writer($renderer);
        $svg = $writer->writeString($content);

        return 'data:image/svg+xml;base64,'.base64_encode($svg);
    }

    protected function resolveFileDataUri(?string $path): ?string
    {
        if (empty($path) || ! file_exists($path)) {
            return null;
        }

        $mime = mime_content_type($path) ?: 'image/svg+xml';

        return 'data:'.$mime.';base64,'.base64_encode(file_get_contents($path));
    }

    protected function resolveStorageDataUri(?string $path): ?string
    {
        if (blank($path)) {
            return null;
        }

        $fullPath = Storage::disk('public')->path($path);

        return $this->resolveFileDataUri($fullPath);
    }

    protected function avatarInitials(?string $name): string
    {
        $trimmed = trim((string) $name);

        if ($trimmed === '') {
            return '--';
        }

        return strtoupper(mb_substr($trimmed, 0, 2));
    }

    protected function displayCardValue(mixed $value): string
    {
        if ($value === null || $value === '') {
            return '-';
        }

        $trimmed = trim((string) $value);

        return $trimmed !== '' ? $trimmed : '-';
    }
}
