/home/kueuepay/public_html/vendor/nunomaduro/termwind/src/ValueObjects/Styles.php
<?php

declare(strict_types=1);

namespace Termwind\ValueObjects;

use Closure;
use Termwind\Actions\StyleToMethod;
use Termwind\Components\Element;
use Termwind\Components\Hr;
use Termwind\Components\Li;
use Termwind\Components\Ol;
use Termwind\Components\Ul;
use Termwind\Enums\Color;
use Termwind\Exceptions\ColorNotFound;
use Termwind\Exceptions\InvalidStyle;
use Termwind\Repositories\Styles as StyleRepository;
use function Termwind\terminal;

/**
 * @internal
 */
final class Styles
{
    /**
     * Finds all the styling on a string.
     */
    public const STYLING_REGEX = "/\<[\w=#\/\;,:.&,%?-]+\>|\\e\[\d+m/";

    /** @var array<int, string> */
    private array $styles = [];

    private ?Element $element = null;

    /**
     * Creates a Style formatter instance.
     *
     * @param  array<string, mixed>  $properties
     * @param  array<string, Closure(string, array<string, string|int>, array<string, int[]>): string>  $textModifiers
     * @param  array<string, Closure(string, array<string, string|int>): string>  $styleModifiers
     * @param  string[]  $defaultStyles
     */
    final public function __construct(
        private array $properties = [
            'colors' => [],
            'options' => [],
            'isFirstChild' => false,
        ],
        private array $textModifiers = [],
        private array $styleModifiers = [],
        private array $defaultStyles = []
    ) {
    }

    /**
     * @param  Element  $element
     * @return $this
     */
    public function setElement(Element $element): self
    {
        $this->element = $element;

        return $this;
    }

    /**
     * Gets default styles.
     *
     * @return string[]
     */
    public function defaultStyles(): array
    {
        return $this->defaultStyles;
    }

    /**
     * Gets the element's style properties.
     *
     * @return array<string, mixed>
     */
    final public function getProperties(): array
    {
        return $this->properties;
    }

    /**
     * Sets the element's style properties.
     *
     * @param  array<string, mixed>  $properties
     */
    public function setProperties(array $properties): self
    {
        $this->properties = $properties;

        return $this;
    }

    /**
     * Sets the styles to the element.
     */
    final public function setStyle(string $style): self
    {
        $this->styles = array_unique(array_merge($this->styles, [$style]));

        return $this;
    }

    /**
     * Checks if the element has the style.
     */
    final public function hasStyle(string $style): bool
    {
        return in_array($style, $this->styles, true);
    }

    /**
     * Adds a style to the element.
     */
    final public function addStyle(string $style): self
    {
        return StyleToMethod::multiple($this, $style);
    }

    /**
     * Inherit styles from given Styles object.
     */
    final public function inheritFromStyles(self $styles): self
    {
        foreach (['ml', 'mr', 'pl', 'pr', 'width', 'minWidth', 'maxWidth', 'spaceY', 'spaceX'] as $style) {
            $this->properties['parentStyles'][$style] = array_merge(
                $this->properties['parentStyles'][$style] ?? [],
                $styles->properties['parentStyles'][$style] ?? []
            );

            $this->properties['parentStyles'][$style][] = $styles->properties['styles'][$style] ?? 0;
        }

        $this->properties['parentStyles']['justifyContent'] = $styles->properties['styles']['justifyContent'] ?? false;

        foreach (['bg', 'fg'] as $colorType) {
            $value = (array) ($this->properties['colors'][$colorType] ?? []);
            $parentValue = (array) ($styles->properties['colors'][$colorType] ?? []);

            if ($value === [] && $parentValue !== []) {
                $this->properties['colors'][$colorType] = $styles->properties['colors'][$colorType];
            }
        }

        if (! is_null($this->properties['options']['bold'] ?? null) ||
            ! is_null($styles->properties['options']['bold'] ?? null)) {
            $this->properties['options']['bold'] = $this->properties['options']['bold']
                ?? $styles->properties['options']['bold']
                ?? false;
        }

        return $this;
    }

    /**
     * Adds a background color to the element.
     */
    final public function bg(string $color, int $variant = 0): self
    {
        return $this->with(['colors' => [
            'bg' => $this->getColorVariant($color, $variant),
        ]]);
    }

    /**
     * Adds a bold style to the element.
     */
    final public function fontBold(): self
    {
        return $this->with(['options' => [
            'bold' => true,
        ]]);
    }

    /**
     * Removes the bold style on the element.
     */
    final public function fontNormal(): self
    {
        return $this->with(['options' => [
            'bold' => false,
        ]]);
    }

    /**
     * Adds a bold style to the element.
     */
    final public function strong(): self
    {
        $this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[1m%s\e[0m", $text);

        return $this;
    }

    /**
     * Adds an italic style to the element.
     */
    final public function italic(): self
    {
        $this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[3m%s\e[0m", $text);

        return $this;
    }

    /**
     * Adds an underline style.
     */
    final public function underline(): self
    {
        $this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[4m%s\e[0m", $text);

        return $this;
    }

    /**
     * Adds the given margin left to the element.
     */
    final public function ml(int $margin): self
    {
        return $this->with(['styles' => [
            'ml' => $margin,
        ]]);
    }

    /**
     * Adds the given margin right to the element.
     */
    final public function mr(int $margin): self
    {
        return $this->with(['styles' => [
            'mr' => $margin,
        ]]);
    }

    /**
     * Adds the given margin bottom to the element.
     */
    final public function mb(int $margin): self
    {
        return $this->with(['styles' => [
            'mb' => $margin,
        ]]);
    }

    /**
     * Adds the given margin top to the element.
     */
    final public function mt(int $margin): self
    {
        return $this->with(['styles' => [
            'mt' => $margin,
        ]]);
    }

    /**
     * Adds the given horizontal margin to the element.
     */
    final public function mx(int $margin): self
    {
        return $this->with(['styles' => [
            'ml' => $margin,
            'mr' => $margin,
        ]]);
    }

    /**
     * Adds the given vertical margin to the element.
     */
    final public function my(int $margin): self
    {
        return $this->with(['styles' => [
            'mt' => $margin,
            'mb' => $margin,
        ]]);
    }

    /**
     * Adds the given margin to the element.
     */
    final public function m(int $margin): self
    {
        return $this->my($margin)->mx($margin);
    }

    /**
     * Adds the given padding left to the element.
     */
    final public function pl(int $padding): static
    {
        return $this->with(['styles' => [
            'pl' => $padding,
        ]]);
    }

    /**
     * Adds the given padding right.
     */
    final public function pr(int $padding): static
    {
        return $this->with(['styles' => [
            'pr' => $padding,
        ]]);
    }

    /**
     * Adds the given horizontal padding.
     */
    final public function px(int $padding): self
    {
        return $this->pl($padding)->pr($padding);
    }

    /**
     * Adds the given padding top.
     */
    final public function pt(int $padding): static
    {
        return $this->with(['styles' => [
            'pt' => $padding,
        ]]);
    }

    /**
     * Adds the given padding bottom.
     */
    final public function pb(int $padding): static
    {
        return $this->with(['styles' => [
            'pb' => $padding,
        ]]);
    }

    /**
     * Adds the given vertical padding.
     */
    final public function py(int $padding): self
    {
        return $this->pt($padding)->pb($padding);
    }

    /**
     * Adds the given padding.
     */
    final public function p(int $padding): self
    {
        return $this->pt($padding)->pr($padding)->pb($padding)->pl($padding);
    }

    /**
     * Adds the given vertical margin to the childs, ignoring the first child.
     */
    final public function spaceY(int $space): self
    {
        return $this->with(['styles' => [
            'spaceY' => $space,
        ]]);
    }

    /**
     * Adds the given horizontal margin to the childs, ignoring the first child.
     */
    final public function spaceX(int $space): self
    {
        return $this->with(['styles' => [
            'spaceX' => $space,
        ]]);
    }

    /**
     * Adds a border on top of each element.
     */
    final public function borderT(int $width = 1): self
    {
        if (! $this->element instanceof Hr) {
            throw new InvalidStyle('`border-t` can only be used on an "hr" element.');
        }

        $this->styleModifiers[__METHOD__] = function ($text, $styles): string {
            $length = $this->getLength($text);
            if ($length < 1) {
                $margins = (int) ($styles['ml'] ?? 0) + ($styles['mr'] ?? 0);

                return str_repeat('─', self::getParentWidth($this->properties['parentStyles'] ?? []) - $margins);
            }

            return str_repeat('─', $length);
        };

        return $this;
    }

    /**
     * Adds a text alignment or color to the element.
     */
    final public function text(string $value, int $variant = 0): self
    {
        if (in_array($value, ['left', 'right', 'center'], true)) {
            return $this->with(['styles' => [
                'text-align' => $value,
            ]]);
        }

        return $this->with(['colors' => [
            'fg' => $this->getColorVariant($value, $variant),
        ]]);
    }

    /**
     * Truncates the text of the element.
     */
    final public function truncate(int $limit = 0, string $end = '…'): self
    {
        $this->textModifiers[__METHOD__] = function ($text, $styles) use ($limit, $end): string {
            $width = $styles['width'] ?? 0;

            if (is_string($width)) {
                $width = self::calcWidthFromFraction(
                    $width,
                    $styles,
                    $this->properties['parentStyles'] ?? []
                );
            }

            [, $paddingRight, , $paddingLeft] = $this->getPaddings();
            $width -= $paddingRight + $paddingLeft;

            $limit = $limit > 0 ? $limit : $width;
            if ($limit === 0) {
                return $text;
            }

            $limit -= mb_strwidth($end, 'UTF-8');

            if ($this->getLength($text) <= $limit) {
                return $text;
            }

            return rtrim(self::trimText($text, $limit).$end);
        };

        return $this;
    }

    /**
     * Forces the width of the element.
     */
    final public function w(int|string $width): static
    {
        return $this->with(['styles' => [
            'width' => $width,
        ]]);
    }

    /**
     * Forces the element width to the full width of the terminal.
     */
    final public function wFull(): static
    {
        return $this->w('1/1');
    }

    /**
     * Removes the width set on the element.
     */
    final public function wAuto(): static
    {
        return $this->with(['styles' => [
            'width' => null,
        ]]);
    }

    /**
     * Defines a minimum width of an element.
     */
    final public function minW(int|string $width): static
    {
        return $this->with(['styles' => [
            'minWidth' => $width,
        ]]);
    }

    /**
     * Defines a maximum width of an element.
     */
    final public function maxW(int|string $width): static
    {
        return $this->with(['styles' => [
            'maxWidth' => $width,
        ]]);
    }

    /**
     * Makes the element's content uppercase.
     */
    final public function uppercase(): self
    {
        $this->textModifiers[__METHOD__] = static fn ($text): string => mb_strtoupper($text, 'UTF-8');

        return $this;
    }

    /**
     * Makes the element's content lowercase.
     */
    final public function lowercase(): self
    {
        $this->textModifiers[__METHOD__] = static fn ($text): string => mb_strtolower($text, 'UTF-8');

        return $this;
    }

    /**
     * Makes the element's content capitalize.
     */
    final public function capitalize(): self
    {
        $this->textModifiers[__METHOD__] = static fn ($text): string => mb_convert_case($text, MB_CASE_TITLE, 'UTF-8');

        return $this;
    }

    /**
     * Makes the element's content in snakecase.
     */
    final public function snakecase(): self
    {
        $this->textModifiers[__METHOD__] = static fn ($text): string => mb_strtolower(
            (string) preg_replace(['/([a-z\d])([A-Z])/', '/([^_])([A-Z][a-z])/'], '$1_$2', $text),
            'UTF-8'
        );

        return $this;
    }

    /**
     * Makes the element's content with a line through.
     */
    final public function lineThrough(): self
    {
        $this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[9m%s\e[0m", $text);

        return $this;
    }

    /**
     * Makes the element's content invisible.
     */
    final public function invisible(): self
    {
        $this->styleModifiers[__METHOD__] = static fn ($text): string => sprintf("\e[8m%s\e[0m", $text);

        return $this;
    }

    /**
     * Do not display element's content.
     */
    final public function hidden(): self
    {
        return $this->with(['styles' => [
            'display' => 'hidden',
        ]]);
    }

    /**
     * Makes a line break before the element's content.
     */
    final public function block(): self
    {
        return $this->with(['styles' => [
            'display' => 'block',
        ]]);
    }

    /**
     * Makes an element eligible to work with flex-1 element's style.
     */
    final public function flex(): self
    {
        return $this->with(['styles' => [
            'display' => 'flex',
        ]]);
    }

    /**
     * Makes an element grow and shrink as needed, ignoring the initial size.
     */
    final public function flex1(): self
    {
        return $this->with(['styles' => [
            'flex-1' => true,
        ]]);
    }

    /**
     * Justifies childs along the element with an equal amount of space between.
     */
    final public function justifyBetween(): self
    {
        return $this->with(['styles' => [
            'justifyContent' => 'between',
        ]]);
    }

    /**
     * Justifies childs along the element with an equal amount of space between
     * each item and half around.
     */
    final public function justifyAround(): self
    {
        return $this->with(['styles' => [
            'justifyContent' => 'around',
        ]]);
    }

    /**
     * Justifies childs along the element with an equal amount of space around each item.
     */
    final public function justifyEvenly(): self
    {
        return $this->with(['styles' => [
            'justifyContent' => 'evenly',
        ]]);
    }

    /**
     * Justifies childs along the center of the container’s main axis.
     */
    final public function justifyCenter(): self
    {
        return $this->with(['styles' => [
            'justifyContent' => 'center',
        ]]);
    }

    /**
     * Repeats the string given until it fills all the content.
     */
    final public function contentRepeat(string $string): self
    {
        $string = preg_replace("/\[?'?([^'|\]]+)'?\]?/", '$1', $string) ?? '';

        $this->textModifiers[__METHOD__] = static fn (): string => str_repeat($string, (int) floor(terminal()->width() / mb_strlen($string, 'UTF-8')));

        return $this->with(['styles' => [
            'contentRepeat' => true,
        ]]);
    }

    /**
     * Prepends text to the content.
     */
    final public function prepend(string $string): self
    {
        $this->textModifiers[__METHOD__] = static fn ($text): string => $string.$text;

        return $this;
    }

    /**
     * Appends text to the content.
     */
    final public function append(string $string): self
    {
        $this->textModifiers[__METHOD__] = static fn ($text): string => $text.$string;

        return $this;
    }

    /**
     * Prepends the list style type to the content.
     */
    final public function list(string $type, int $index = 0): self
    {
        if (! $this->element instanceof Ul && ! $this->element instanceof Ol && ! $this->element instanceof Li) {
            throw new InvalidStyle(sprintf(
                'Style list-none cannot be used with %s',
                $this->element !== null ? $this->element::class : 'unknown element'
            ));
        }

        if (! $this->element instanceof Li) {
            return $this;
        }

        return match ($type) {
            'square' => $this->prepend('▪ '),
            'disc' => $this->prepend('• '),
            'decimal' => $this->prepend(sprintf('%d. ', $index)),
            default => $this,
        };
    }

    /**
     * Adds the given properties to the element.
     *
     * @param  array<string, mixed>  $properties
     */
    public function with(array $properties): self
    {
        $this->properties = array_replace_recursive($this->properties, $properties);

        return $this;
    }

    /**
     * Sets the href property to the element.
     */
    final public function href(string $href): self
    {
        $href = str_replace('%', '%%', $href);

        return $this->with(['href' => array_filter([$href])]);
    }

    /**
     * Formats a given string.
     */
    final public function format(string $content): string
    {
        foreach ($this->textModifiers as $modifier) {
            $content = $modifier(
                $content,
                $this->properties['styles'] ?? [],
                $this->properties['parentStyles'] ?? []
            );
        }

        $content = $this->applyWidth($content);

        foreach ($this->styleModifiers as $modifier) {
            $content = $modifier($content, $this->properties['styles'] ?? []);
        }

        return $this->applyStyling($content);
    }

    /**
     * Get the format string including required styles.
     */
    private function getFormatString(): string
    {
        $styles = [];

        /** @var array<int, string> $href */
        $href = $this->properties['href'] ?? [];
        if ($href !== []) {
            $styles[] = sprintf('href=%s', array_pop($href));
        }

        $colors = $this->properties['colors'] ?? [];

        foreach ($colors as $option => $content) {
            if (in_array($option, ['fg', 'bg'], true)) {
                $content = is_array($content) ? array_pop($content) : $content;

                $styles[] = "$option=$content";
            }
        }

        $options = $this->properties['options'] ?? [];

        if ($options !== []) {
            $options = array_keys(array_filter(
                $options, fn ($option) => $option === true
            ));
            $styles[] = count($options) > 0
                ? 'options='.implode(',', $options)
                : 'options=,';
        }

        // If there are no styles we don't need extra tags
        if ($styles === []) {
            return '%s%s%s%s%s';
        }

        return '%s<'.implode(';', $styles).'>%s%s%s</>%s';
    }

    /**
     * Get the margins applied to the element.
     *
     * @return array{0: int, 1: int, 2: int, 3: int}
     */
    private function getMargins(): array
    {
        $isFirstChild = (bool) $this->properties['isFirstChild'];

        $spaceY = $this->properties['parentStyles']['spaceY'] ?? [];
        $spaceY = ! $isFirstChild ? end($spaceY) : 0;

        $spaceX = $this->properties['parentStyles']['spaceX'] ?? [];
        $spaceX = ! $isFirstChild ? end($spaceX) : 0;

        return [
            $spaceY > 0 ? $spaceY : $this->properties['styles']['mt'] ?? 0,
            $this->properties['styles']['mr'] ?? 0,
            $this->properties['styles']['mb'] ?? 0,
            $spaceX > 0 ? $spaceX : $this->properties['styles']['ml'] ?? 0,
        ];
    }

    /**
     * Get the paddings applied to the element.
     *
     * @return array{0: int, 1: int, 2: int, 3: int}
     */
    private function getPaddings(): array
    {
        return [
            $this->properties['styles']['pt'] ?? 0,
            $this->properties['styles']['pr'] ?? 0,
            $this->properties['styles']['pb'] ?? 0,
            $this->properties['styles']['pl'] ?? 0,
        ];
    }

    /**
     * It applies the correct width for the content.
     */
    private function applyWidth(string $content): string
    {
        $styles = $this->properties['styles'] ?? [];
        $minWidth = $styles['minWidth'] ?? -1;
        $width = max($styles['width'] ?? -1, $minWidth);
        $maxWidth = $styles['maxWidth'] ?? 0;

        if ($width < 0) {
            return $content;
        }

        if ($width === 0) {
            return '';
        }

        if (is_string($width)) {
            $width = self::calcWidthFromFraction(
                $width,
                $styles,
                $this->properties['parentStyles'] ?? []
            );
        }

        if ($maxWidth > 0) {
            $width = min($styles['maxWidth'], $width);
        }

        $width -= ($styles['pl'] ?? 0) + ($styles['pr'] ?? 0);
        $length = $this->getLength($content);

        preg_match_all("/\n+/", $content, $matches);

        $width *= count($matches[0] ?? []) + 1;
        $width += mb_strlen($matches[0][0] ?? '', 'UTF-8');

        if ($length <= $width) {
            $space = $width - $length;

            return match ($styles['text-align'] ?? '') {
                'right' => str_repeat(' ', $space).$content,
                'center' => str_repeat(' ', (int) floor($space / 2)).$content.str_repeat(' ', (int) ceil($space / 2)),
                default => $content.str_repeat(' ', $space),
            };
        }

        return self::trimText($content, $width);
    }

    /**
     * It applies the styling for the content.
     */
    private function applyStyling(string $content): string
    {
        $display = $this->properties['styles']['display'] ?? 'inline';

        if ($display === 'hidden') {
            return '';
        }

        $isFirstChild = (bool) $this->properties['isFirstChild'];

        [$marginTop, $marginRight, $marginBottom, $marginLeft] = $this->getMargins();
        [$paddingTop, $paddingRight, $paddingBottom, $paddingLeft] = $this->getPaddings();

        $content = (string) preg_replace('/\r[ \t]?/', "\n",
            (string) preg_replace(
                '/\n/',
                str_repeat(' ', $marginRight + $paddingRight)
                ."\n".
                str_repeat(' ', $marginLeft + $paddingLeft),
                $content)
        );

        $formatted = sprintf(
            $this->getFormatString(),
            str_repeat(' ', $marginLeft),
            str_repeat(' ', $paddingLeft),
            $content,
            str_repeat(' ', $paddingRight),
            str_repeat(' ', $marginRight),
        );

        $empty = str_replace(
            $content,
            str_repeat(' ', $this->getLength($content)),
            $formatted
        );

        $items = [];

        if (in_array($display, ['block', 'flex'], true) && ! $isFirstChild) {
            $items[] = "\n";
        }

        if ($marginTop > 0) {
            $items[] = str_repeat("\n", $marginTop);
        }

        if ($paddingTop > 0) {
            $items[] = $empty."\n";
        }

        $items[] = $formatted;

        if ($paddingBottom > 0) {
            $items[] = "\n".$empty;
        }

        if ($marginBottom > 0) {
            $items[] = str_repeat("\n", $marginBottom);
        }

        return implode('', $items);
    }

    /**
     * Get the length of the text provided without the styling tags.
     */
    public function getLength(string $text = null): int
    {
        return mb_strlen(preg_replace(
            self::STYLING_REGEX,
            '',
            $text ?? $this->element?->toString() ?? ''
        ) ?? '', 'UTF-8');
    }

    /**
     * Get the length of the element without margins.
     */
    public function getInnerWidth(): int
    {
        $innerLength = $this->getLength();
        [, $marginRight, , $marginLeft] = $this->getMargins();

        return $innerLength - $marginLeft - $marginRight;
    }

    /**
     * Get the constant variant color from Color class.
     */
    private function getColorVariant(string $color, int $variant): string
    {
        if ($variant > 0) {
            $color .= '-'.$variant;
        }

        if (StyleRepository::has($color)) {
            return StyleRepository::get($color)->getColor();
        }

        $colorConstant = mb_strtoupper(str_replace('-', '_', $color), 'UTF-8');

        if (! defined(Color::class."::$colorConstant")) {
            throw new ColorNotFound($colorConstant);
        }

        return constant(Color::class."::$colorConstant");
    }

    /**
     * Calculates the width based on the fraction provided.
     *
     * @param  array<string, int>  $styles
     * @param  array<string, array<int, int|string>>  $parentStyles
     */
    private static function calcWidthFromFraction(string $fraction, array $styles, array $parentStyles): int
    {
        $width = self::getParentWidth($parentStyles);

        preg_match('/(\d+)\/(\d+)/', $fraction, $matches);

        if (count($matches) !== 3 || $matches[2] === '0') {
            throw new InvalidStyle(sprintf('Style [%s] is invalid.', "w-$fraction"));
        }

        /** @@phpstan-ignore-next-line  */
        $width = (int) floor($width * $matches[1] / $matches[2]);
        $width -= ($styles['ml'] ?? 0) + ($styles['mr'] ?? 0);

        return $width;
    }

    /**
     * Gets the width of the parent element.
     *
     * @param  array<string, array<int|string>>  $styles
     */
    public static function getParentWidth(array $styles): int
    {
        $width = terminal()->width();
        foreach ($styles['width'] ?? [] as $index => $parentWidth) {
            $minWidth = (int) $styles['minWidth'][$index];
            $maxWidth = (int) $styles['maxWidth'][$index];
            $margins = (int) $styles['ml'][$index] + (int) $styles['mr'][$index];

            $parentWidth = max($parentWidth, $minWidth);

            if ($parentWidth < 1) {
                $parentWidth = $width;
            } elseif (is_int($parentWidth)) {
                $parentWidth += $margins;
            }

            preg_match('/(\d+)\/(\d+)/', (string) $parentWidth, $matches);

            $width = count($matches) !== 3
                ? (int) $parentWidth
                : (int) floor($width * $matches[1] / $matches[2]); //@phpstan-ignore-line

            if ($maxWidth > 0) {
                $width = min($maxWidth, $width);
            }

            $width -= $margins;
            $width -= (int) $styles['pl'][$index] + (int) $styles['pr'][$index];
        }

        return $width;
    }

    /**
     * It trims the text properly ignoring all escape codes and
     * `<bg;fg;options>` tags.
     */
    private static function trimText(string $text, int $width): string
    {
        preg_match_all(self::STYLING_REGEX, $text, $matches, PREG_OFFSET_CAPTURE);
        $text = rtrim(mb_strimwidth(preg_replace(self::STYLING_REGEX, '', $text) ?? '', 0, $width, '', 'UTF-8'));

        foreach ($matches[0] ?? [] as [$part, $index]) {
            $text = substr($text, 0, $index).$part.substr($text, $index, null);
        }

        return $text;
    }
}
Kueue Pay | Contactless Payment System
top

Quick Steps to NFC Pay

Getting started with NFC Pay is simple and quick. Register your account, add your cards, and you're ready to make payments in no time. Whether you're paying at a store, sending money to a friend, or managing your merchant transactions, NFC Pay makes it easy and secure.

1

Register Your Account

Download the NFC Pay app and sign up with your email or phone number. Complete the registration process by verifying your identity, and set up your secure PIN to protect your account.

2

Add Your Cards

Link your debit or credit cards to your NFC Pay wallet. Simply scan your card or enter the details manually, and you’re set to load funds, shop, and pay with ease.

3

Make Payment

To pay, simply tap your phone or scan the QR code at checkout. You can also transfer money to other users with a few taps. Enjoy fast, contactless payments with top-notch security.

Advanced Security Features Designed to Protect Your Information Effectively

NFC Pay prioritizes your security with advanced features that safeguard every transaction. From SMS or email verification to end-to-end encryption, we've implemented robust measures to ensure your data is always protected. Our security systems are designed to prevent unauthorized access and provide you with a safe and reliable payment experience.

img

SMS or Email Verification

Receive instant alerts for every transaction to keep track of your account activities.

img

KYC Solution

Verify your identity through our Know Your Customer process to prevent fraud and enhance security.

img

Two Factor Authentication

Dramatically supply transparent backward deliverables before caward comp internal or "organic" sources.

img

End-to-End Encryption

All your data and transactions are encrypted, ensuring that your sensitive information remains private.

img

Behavior Tracking

Monitor unusual activity patterns to detect and prevent suspicious behavior in real-time.

Top Reasons to Choose Us for Reliable and Expert Solutions

With NFC Pay, you get a trusted platform backed by proven expertise and a commitment to quality. We put our customers first, offering innovative solutions tailored to your needs, ensuring every transaction is secure, swift, and seamless.

1

Proven Expertise

Our team brings years of experience in the digital payments industry to provide reliable services.

2

Commitment to Quality

We prioritize excellence, ensuring that every aspect of our platform meets the highest standards.

3

Customer-Centric Approach

Your needs drive our solutions, and we are dedicated to delivering a superior user experience.

4

Innovative Solutions

We continuously evolve, integrating the latest technologies to enhance your payment experience.

Customer Feedback: Real Experiences from Satisfied Clients and Partners

Hear from our users who trust NFC Pay for their everyday transactions. Our commitment to security, ease of use, and exceptional service shines through in their experiences. See why our clients choose NFC Pay for their payment needs and how it has transformed the way they manage their finances.

"NFC Pay has made my transactions incredibly simple and secure. The intuitive interface and quick payment options are game-changers for my business"

"I love how NFC Pay prioritizes security without compromising on convenience. The two-factor authentication and instant alerts give me peace of mind every time I use it."

"Setting up my merchant account was a breeze, and now I can accept payments effortlessly. NFC Pay has truly streamlined my operations, saving me time and hassle."

Get the NFC Pay App for Seamless Transactions Anytime, Anywhere

Unlock the full potential of NFC Pay by downloading our app, designed to bring secure, swift, and smart transactions to your fingertips. Whether you're paying at a store, transferring money to friends, or managing your business payments, the NFC Pay app makes it effortless. Available on both iOS and Android, it's your all-in-one solution for convenient and reliable digital payments. Download now and experience the future of payments!

img