<?php

namespace App\Support;

use DateTimeInterface;

class Jalali
{
    public const MONTHS = [
        1 => 'فروردین', 2 => 'اردیبهشت', 3 => 'خرداد',
        4 => 'تیر',     5 => 'مرداد',    6 => 'شهریور',
        7 => 'مهر',     8 => 'آبان',     9 => 'آذر',
        10 => 'دی',     11 => 'بهمن',   12 => 'اسفند',
    ];

    /**
     * Convert any DateTime to a Jalali-formatted string.
     * Supported tokens: Y (year), m (month, 2-digit), n (month, no pad),
     * F (Persian month name), d (day, 2-digit), j (day, no pad), H, i, s.
     */
    public static function format(?DateTimeInterface $dt, string $format = 'Y/m/d'): string
    {
        if (!$dt) {
            return '';
        }

        [$jy, $jm, $jd] = self::gregorianToJalali(
            (int) $dt->format('Y'),
            (int) $dt->format('n'),
            (int) $dt->format('j')
        );

        $replacements = [
            'Y' => (string) $jy,
            'm' => sprintf('%02d', $jm),
            'n' => (string) $jm,
            'F' => self::MONTHS[$jm] ?? '',
            'd' => sprintf('%02d', $jd),
            'j' => (string) $jd,
            'H' => $dt->format('H'),
            'i' => $dt->format('i'),
            's' => $dt->format('s'),
        ];

        return strtr($format, $replacements);
    }

    public static function gregorianToJalali(int $gy, int $gm, int $gd): array
    {
        $g_days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        $j_days_in_month = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29];

        $gy2 = ($gm > 2) ? $gy + 1 : $gy;
        $days = 355666
            + (365 * $gy)
            + (int) (($gy2 + 3) / 4)
            - (int) (($gy2 + 99) / 100)
            + (int) (($gy2 + 399) / 400)
            + $gd;
        for ($i = 0; $i < $gm - 1; $i++) {
            $days += $g_days_in_month[$i];
        }

        $jy = -1595;
        $jy += 33 * (int) ($days / 12053);
        $days %= 12053;
        $jy += 4 * (int) ($days / 1461);
        $days %= 1461;

        if ($days > 365) {
            $jy += (int) (($days - 1) / 365);
            $days = ($days - 1) % 365;
        }

        $i = 0;
        for (; $i < 11 && $days >= $j_days_in_month[$i]; $i++) {
            $days -= $j_days_in_month[$i];
        }
        $jm = $i + 1;
        $jd = $days + 1;

        return [$jy, $jm, $jd];
    }
}
