<?php

namespace App\Services\Badges;

use FPDF;

class BadgeTextFormatter
{
    public function normalizeIds(array $ids): array
    {
        return array_values(array_unique(array_filter(array_map(static function ($v) {
            if (is_string($v)) {
                $v = trim($v);
            }

            if ($v === '' || $v === null) {
                return null;
            }

            return (int) $v;
        }, $ids), static fn ($v) => $v !== null && $v > 0)));
    }

    public function norm(?string $s): string
    {
        $s = (string) $s;
        $s = str_replace(["\xC2\xA0", "\xA0"], ' ', $s);
        $s = preg_replace('/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/u', '', $s) ?? $s;
        $s = preg_replace('/\s+/u', ' ', $s) ?? $s;

        return trim($s);
    }

    public function toPdf(string $s): string
    {
        if (function_exists('iconv')) {
            $o = @iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $s);
            if ($o !== false && $o !== '') {
                return $o;
            }
        }

        if (function_exists('mb_convert_encoding')) {
            $o = @mb_convert_encoding($s, 'ISO-8859-1', 'UTF-8');
            if ($o !== '') {
                return $o;
            }
        }

        $o = @utf8_decode($s);

        return $o !== '' ? $o : 'STAFF';
    }

    public function fitText(FPDF $pdf, string $text, int $startSize, int $minSize, float $maxWidth): int
    {
        $size = $startSize;

        while ($size >= $minSize) {
            $pdf->SetFontSize($size);
            if ($pdf->GetStringWidth($text) <= $maxWidth) {
                return $size;
            }
            $size--;
        }

        return $minSize;
    }

    public function formatRole(?string $role): string
    {
        $role = (string) $role;
        $role = str_replace(['-', '_'], ' ', $role);
        $role = preg_replace('/\s+/u', ' ', trim($role));

        if ($role === '') {
            return '';
        }

        $special = [
            'of'   => 'of',
            'head' => 'Head',
        ];

        $tokens = explode(' ', $role);
        $out = [];

        foreach ($tokens as $tok) {
            if ($tok === '') {
                continue;
            }

            $core = preg_replace('/^\P{L}+|\P{L}+$/u', '', $tok);
            $start = strpos($tok, $core);

            if ($start === false) {
                $out[] = ucfirst(mb_strtolower($tok, 'UTF-8'));
                continue;
            }

            $pre = substr($tok, 0, $start);
            $suf = substr($tok, $start + strlen($core));
            $lw = mb_strtolower($core, 'UTF-8');

            if (isset($special[$lw])) {
                $coreFmt = $special[$lw];
            } elseif (preg_match('/^\p{L}{1,4}$/u', $core)) {
                $coreFmt = mb_strtoupper($core, 'UTF-8');
            } else {
                $coreFmt = preg_replace_callback(
                    '/\p{L}+/u',
                    static fn ($m) => mb_strtoupper(mb_substr($m[0], 0, 1, 'UTF-8'), 'UTF-8')
                        . mb_strtolower(mb_substr($m[0], 1, null, 'UTF-8'), 'UTF-8'),
                    mb_strtolower($core, 'UTF-8')
                );
            }

            $out[] = $pre . $coreFmt . $suf;
        }

        return implode(' ', $out);
    }

    public function formatRolesCsv(?string $csv): string
    {
        if ($csv === null) {
            return '';
        }

        $parts = array_filter(array_map('trim', explode(',', (string) $csv)), 'strlen');

        if (empty($parts)) {
            return '';
        }

        return implode(', ', array_map(fn ($r) => $this->formatRole($r), $parts));
    }

    public function formatClass(string $class): string
    {
        $c = trim($class);

        if ($c === '') {
            return '';
        }

        $lc = strtolower($c);

        if ($lc === 'kg' || $lc === 'kindergarten') {
            return 'KG';
        }

        if ($lc === 'youth') {
            return 'Youth';
        }

        return $c;
    }

    public function resolveRole(array $info): string
    {
        $candidates = [
            'role',
            'active_role',
            'role_name',
            fn ($r) => !empty($r['roles'])
                ? (array_values(array_filter(array_map('trim', explode(',', (string) $r['roles']))))[0] ?? '')
                : '',
            'job_title',
            'title',
            'position',
            'staff_role',
            'department_role',
            'dept_role',
        ];

        foreach ($candidates as $key) {
            if (is_callable($key)) {
                $v = $key($info);
                if ($this->norm($v) !== '') {
                    return $this->norm($v);
                }
            } else {
                if (!empty($info[$key])) {
                    $v = $this->norm((string) $info[$key]);
                    if ($v !== '') {
                        return $v;
                    }
                }
            }
        }

        return 'STAFF';
    }

    public function firstExisting(array $paths): ?string
    {
        foreach ($paths as $path) {
            if (!empty($path) && file_exists($path)) {
                return $path;
            }
        }

        return null;
    }
}
