<?php
namespace Helpers\Outil;

class StringHelper
{
    public static function removePrefix(string $text, string $prefix) :string
    {
        if (str_starts_with($text, $prefix)) {
            $text = substr($text, strlen($prefix)).'';
        }
        return $text;
    }

    public static function utf8Encode(string $s): string
    {
        return (string)mb_convert_encoding($s, 'UTF-8', 'ISO-8859-1');
    }
    
    public static function utf8Decode(string $s): string
    {
        return (string)mb_convert_encoding($s, 'ISO-8859-1', 'UTF-8');
    }

    /**
     *
     * Removes len character from $s, starting at and including $pos, and add $add in their place.
     * @source https://stackoverflow.com/questions/20817618/is-there-a-splice-method-for-strings
     */
    public static function splice(string $s, int $pos, int $length, ?string $add = null) :string
    {
        // We cannot pass negative indexes directly to the 2nd slicing operation.
        if ($pos < 0) {
            throw new \Exception('invalid position '.$pos);
        }

        return substr($s, 0, $pos)
            . ($add ?? '')
            . substr($s, $pos + $length);
    }

    public static function replaceCallback(
        string $subject,
        string $needle,
        callable $fn
    ): string {
        $i = 0;
        while (($i = strpos($subject, $needle)) !== false) {
            $subject = self::splice(
                $subject,
                $i,
                strlen($needle),
                $fn()
            );
        }
        return $subject;
    }

    /**
     * Similar to fputcsv without a stream
     * @param array<string> $ar
     */
    public static function toCsv(array $ar) :string
    {
        $fd = fopen('php://memory', 'rw');
        if ($fd === false) {
            throw new \Exception('fail fopen');
        }
        fputcsv($fd, $ar);
        rewind($fd);
        $line = fgets($fd);
        $res = trim($line ? $line : '');
        rewind($fd);
        fclose($fd);
        return $res;
    }

    public static function truncate(string $str, int $limit) :string
    {
        if (mb_strlen($str) > $limit) {
            return rtrim(mb_substr($str, 0, $limit)) . '…';
        }
        return $str;
    }

    public static function looseSearchMatch(string $search, string $subject) :bool
    {
        return !empty(preg_match(
            '#'
            . implode('.{0,3}', array_map('preg_quote', str_split($search)))
            . '#i',
            $subject
        ));
    }

    // TODO : merge with
    public static function isUrlLoose(string $str) :bool
    {
        return substr($str, 0, 7) == 'http://'
                || substr($str, 0, 8) == 'https://'
                || substr($str, 0, 4) == 'www.'
        ;
    }

    /**
     * @param mixed $var
     */
    public static function isStringable($var) :bool
    {
        return $var === null
            || is_scalar($var)
            || (is_object($var) && method_exists($var, '__toString'))
            || ($var instanceof \Stringable)
        ;
    }
}
