<?php

namespace App\Services\Mail;

/**
 * IMAP değiştirilmiş UTF-7 (RFC 3501 §5.1.3) çeviricisi.
 *
 * Sunucular klasör adlarını bu kodlamada tutar: "Silinmiş Öğeler" →
 * "Silinmi&AV8-  ...". PHP'nin UTF7-IMAP dönüşümü yalnızca ext-imap ile
 * geldiğinden burada elle uygulanır.
 */
class ImapUtf7
{
    /** mUTF-7 → UTF-8 */
    public static function decode(string $value): string
    {
        if (! str_contains($value, '&')) {
            return $value;
        }

        $out = '';
        $length = strlen($value);

        for ($i = 0; $i < $length; $i++) {
            if ($value[$i] !== '&') {
                $out .= $value[$i];

                continue;
            }

            $end = strpos($value, '-', $i + 1);
            if ($end === false) {
                $out .= substr($value, $i);
                break;
            }

            $chunk = substr($value, $i + 1, $end - $i - 1);
            $i = $end;

            if ($chunk === '') {   // "&-" → tek "&"
                $out .= '&';

                continue;
            }

            $base64 = str_replace(',', '/', $chunk);
            $base64 .= str_repeat('=', (4 - strlen($base64) % 4) % 4);
            $utf16 = base64_decode($base64, true);

            if ($utf16 === false) {
                $out .= '&'.$chunk.'-';

                continue;
            }

            $converted = @mb_convert_encoding($utf16, 'UTF-8', 'UTF-16BE');
            $out .= $converted !== false ? $converted : $chunk;
        }

        return $out;
    }

    /** UTF-8 → mUTF-7 */
    public static function encode(string $value): string
    {
        $out = '';
        $buffer = '';

        $chars = preg_split('//u', $value, -1, PREG_SPLIT_NO_EMPTY) ?: [];

        $flush = function () use (&$buffer, &$out) {
            if ($buffer === '') {
                return;
            }
            $utf16 = mb_convert_encoding($buffer, 'UTF-16BE', 'UTF-8');
            $b64 = rtrim(base64_encode((string) $utf16), '=');
            $out .= '&'.str_replace('/', ',', $b64).'-';
            $buffer = '';
        };

        foreach ($chars as $char) {
            $code = mb_ord($char, 'UTF-8');

            if ($char === '&') {
                $flush();
                $out .= '&-';

                continue;
            }

            if ($code !== false && $code >= 0x20 && $code <= 0x7E) {
                $flush();
                $out .= $char;

                continue;
            }

            $buffer .= $char;
        }

        $flush();

        return $out;
    }
}
