<?php

namespace App\Support;

class NumberToWords
{
    protected static array $yekan = ['', 'یک', 'دو', 'سه', 'چهار', 'پنج', 'شش', 'هفت', 'هشت', 'نه'];

    protected static array $dahyek = ['ده', 'یازده', 'دوازده', 'سیزده', 'چهارده', 'پانزده', 'شانزده', 'هفده', 'هجده', 'نوزده'];

    protected static array $dahgan = ['', '', 'بیست', 'سی', 'چهل', 'پنجاه', 'شصت', 'هفتاد', 'هشتاد', 'نود'];

    protected static array $sadgan = ['', 'صد', 'دویست', 'سیصد', 'چهارصد', 'پانصد', 'ششصد', 'هفتصد', 'هشتصد', 'نهصد'];

    protected static array $scale = ['', ' هزار', ' میلیون', ' میلیارد', ' بیلیون', ' بیلیارد'];

    /**
     * تبدیل عدد به حروف فارسی.
     */
    public static function fa(int|float $number): string
    {
        $number = (int) round($number);

        if ($number === 0) {
            return 'صفر';
        }

        $negative = $number < 0;
        $number = abs($number);

        // تقسیم به گروه‌های سه‌رقمی
        $groups = [];
        while ($number > 0) {
            $groups[] = $number % 1000;
            $number = intdiv($number, 1000);
        }

        $parts = [];
        for ($i = count($groups) - 1; $i >= 0; $i--) {
            if ($groups[$i] === 0) {
                continue;
            }
            $parts[] = static::threeDigits($groups[$i]) . (static::$scale[$i] ?? '');
        }

        $result = implode(' و ', $parts);

        return $negative ? "منفی {$result}" : $result;
    }

    /**
     * مبلغ به حروف همراه با واحد ریال.
     */
    public static function rials(int|float $number): string
    {
        return static::fa($number) . ' ریال';
    }

    /**
     * تبدیل ارقام لاتین به فارسی.
     */
    public static function digits(string|int|float|null $value): string
    {
        if ($value === null) {
            return '';
        }

        return strtr((string) $value, [
            '0' => '۰', '1' => '۱', '2' => '۲', '3' => '۳', '4' => '۴',
            '5' => '۵', '6' => '۶', '7' => '۷', '8' => '۸', '9' => '۹',
        ]);
    }

    /**
     * عدد با جداکننده‌ی هزارگان و ارقام فارسی.
     */
    public static function money(int|float|null $number): string
    {
        return static::digits(number_format((float) $number));
    }

    protected static function threeDigits(int $num): string
    {
        $out = [];

        $sad = intdiv($num, 100);
        $rest = $num % 100;

        if ($sad > 0) {
            $out[] = static::$sadgan[$sad];
        }

        if ($rest >= 10 && $rest <= 19) {
            $out[] = static::$dahyek[$rest - 10];
        } else {
            $dah = intdiv($rest, 10);
            $yek = $rest % 10;
            if ($dah > 0) {
                $out[] = static::$dahgan[$dah];
            }
            if ($yek > 0) {
                $out[] = static::$yekan[$yek];
            }
        }

        return implode(' و ', $out);
    }
}
