<?php

namespace App\Services\Documents;

use App\Models\Branch;
use App\Models\DocumentSequence;
use Carbon\Carbon;
use Carbon\CarbonInterface;
use Illuminate\Support\Facades\DB;

final class DocumentNumberService
{
    public function next(int $companyId, int $branchId, string $type, CarbonInterface|string $date): string
    {
        $date = $date instanceof CarbonInterface ? $date : Carbon::parse($date);

        return DB::transaction(function () use ($companyId, $branchId, $type, $date): string {
            $branch = Branch::query()
                ->where('company_id', $companyId)
                ->whereKey($branchId)
                ->lockForUpdate()
                ->firstOrFail();
            $key = [
                'company_id' => $companyId,
                'branch_id' => $branchId,
                'document_type' => strtoupper(trim($type)),
                'year' => (int) $date->format('Y'),
                'month' => (int) $date->format('m'),
            ];

            DocumentSequence::query()->insertOrIgnore($key + [
                'last_number' => 0,
                'pattern' => (string) config('accounting.document_number_pattern'),
                'created_at' => now(),
                'updated_at' => now(),
            ]);

            $sequence = DocumentSequence::query()
                ->where($key)
                ->lockForUpdate()
                ->firstOrFail();
            $sequence->last_number = (int) $sequence->last_number + 1;
            $sequence->save();

            return strtr($sequence->pattern, [
                '{BRANCH}' => $branch->code,
                '{TYPE}' => strtoupper($type),
                '{YEAR}' => $date->format('Y'),
                '{MONTH}' => $date->format('m'),
                '{SEQUENCE}' => str_pad((string) $sequence->last_number, 6, '0', STR_PAD_LEFT),
            ]);
        }, 3);
    }
}
