<?php

namespace App\Http\Controllers;

use App\Models\School;
use DateTimeInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;

abstract class Controller
{
    protected function currentSchoolId(Request $request): ?int
    {
        $schoolId = $request->user()?->school_id;

        if ($schoolId) {
            return (int) $schoolId;
        }

        return School::query()->value('id');
    }

    protected function faDigits(int|float|string|null $value): string
    {
        if ($value === null || $value === '') {
            return '—';
        }

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

    protected function jalaliDate(DateTimeInterface|string|null $value, bool $withTime = false): string
    {
        if (! $value) {
            return '—';
        }

        $date = $value instanceof DateTimeInterface ? Carbon::instance($value) : Carbon::parse($value);
        [$year, $month, $day] = $this->gregorianToJalali((int) $date->format('Y'), (int) $date->format('m'), (int) $date->format('d'));
        $formatted = sprintf('%04d/%02d/%02d', $year, $month, $day);

        if ($withTime) {
            $formatted .= ' '.$date->format('H:i');
        }

        return $this->faDigits($formatted);
    }

    /**
     * Converts Gregorian date to Jalali using the standard arithmetic algorithm.
     *
     * @return array{0:int,1:int,2:int}
     */
    private function gregorianToJalali(int $gy, int $gm, int $gd): array
    {
        $gDaysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        $jDaysInMonth = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29];

        $gy -= 1600;
        $gm -= 1;
        $gd -= 1;

        $gDayNo = 365 * $gy + intdiv($gy + 3, 4) - intdiv($gy + 99, 100) + intdiv($gy + 399, 400);

        for ($i = 0; $i < $gm; $i++) {
            $gDayNo += $gDaysInMonth[$i];
        }

        if ($gm > 1 && (($gy + 1600) % 4 === 0 && (($gy + 1600) % 100 !== 0 || ($gy + 1600) % 400 === 0))) {
            $gDayNo++;
        }

        $gDayNo += $gd;
        $jDayNo = $gDayNo - 79;
        $jNp = intdiv($jDayNo, 12053);
        $jDayNo %= 12053;
        $jy = 979 + 33 * $jNp + 4 * intdiv($jDayNo, 1461);
        $jDayNo %= 1461;

        if ($jDayNo >= 366) {
            $jy += intdiv($jDayNo - 1, 365);
            $jDayNo = ($jDayNo - 1) % 365;
        }

        for ($i = 0; $i < 11 && $jDayNo >= $jDaysInMonth[$i]; $i++) {
            $jDayNo -= $jDaysInMonth[$i];
        }

        return [$jy, $i + 1, $jDayNo + 1];
    }
}
