<?php

namespace App\Services;

use InvalidArgumentException;

class Code39BarcodeService
{
    private const PATTERNS = [
        '0'=>'nnnwwnwnn','1'=>'wnnwnnnnw','2'=>'nnwwnnnnw','3'=>'wnwwnnnnn','4'=>'nnnwwnnnw','5'=>'wnnwwnnnn','6'=>'nnwwwnnnn','7'=>'nnnwnnwnw','8'=>'wnnwnnwnn','9'=>'nnwwnnwnn',
        'A'=>'wnnnnwnnw','B'=>'nnwnnwnnw','C'=>'wnwnnwnnn','D'=>'nnnnwwnnw','E'=>'wnnnwwnnn','F'=>'nnwnwwnnn','G'=>'nnnnnwwnw','H'=>'wnnnnwwnn','I'=>'nnwnnwwnn','J'=>'nnnnwwwnn',
        'K'=>'wnnnnnnww','L'=>'nnwnnnnww','M'=>'wnwnnnnwn','N'=>'nnnnwnnww','O'=>'wnnnwnnwn','P'=>'nnwnwnnwn','Q'=>'nnnnnnwww','R'=>'wnnnnnwwn','S'=>'nnwnnnwwn','T'=>'nnnnwnwwn',
        'U'=>'wwnnnnnnw','V'=>'nwwnnnnnw','W'=>'wwwnnnnnn','X'=>'nwnnwnnnw','Y'=>'wwnnwnnnn','Z'=>'nwwnwnnnn','-'=>'nwnnnnwnw','.'=>'wwnnnnwnn',' '=>'nwwnnnwnn','$'=>'nwnwnwnnn','/'=>'nwnwnnnwn','+'=>'nwnnnwnwn','%'=>'nnnwnwnwn','*'=>'nwnnwnwnn',
    ];

    public function svg(string $value, int $height = 72, int $narrow = 2, int $wide = 5): string
    {
        $value = strtoupper(trim($value));
        if ($value === '' || preg_match('/[^0-9A-Z\. \-\$\/\+%]/', $value)) {
            throw new InvalidArgumentException('Value contains unsupported Code 39 characters.');
        }

        $encoded = '*'.$value.'*';
        $x = 10;
        $bars = '';

        foreach (str_split($encoded) as $char) {
            $pattern = self::PATTERNS[$char];
            foreach (str_split($pattern) as $index => $widthType) {
                $width = $widthType === 'w' ? $wide : $narrow;
                if ($index % 2 === 0) {
                    $bars .= '<rect x="'.$x.'" y="4" width="'.$width.'" height="'.$height.'" fill="currentColor"/>';
                }
                $x += $width;
            }
            $x += $narrow;
        }

        $svgHeight = $height + 28;
        $escaped = htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');

        return '<svg xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Barcode '.$escaped.'" viewBox="0 0 '.($x + 10).' '.$svgHeight.'" width="100%" height="'.$svgHeight.'"><g>'.$bars.'</g><text x="'.(($x + 10) / 2).'" y="'.($height + 22).'" text-anchor="middle" font-family="monospace" font-size="12" fill="currentColor">'.$escaped.'</text></svg>';
    }
}
