"""Short, unique sequential document numbers for sales and purchases."""

from __future__ import annotations

from django.db import models
from django.utils import timezone

# New format: S26-0001 (sale), P26-0001 (purchase)
_LEGACY_PREFIXES: dict[str, tuple[str, ...]] = {
    'S': (lambda y: f'INV-GEN-{y}-',),
    'P': (lambda y: f'PUR-{y}-',),
}


def _trailing_sequence(value: str) -> int | None:
    if not value or '-' not in value:
        return None
    suffix = value.rsplit('-', 1)[-1]
    return int(suffix) if suffix.isdigit() else None


def _max_sequence_for_prefixes(
    queryset: models.QuerySet,
    field: str,
    prefixes: tuple[str, ...],
) -> int:
    max_seq = 0
    for value in queryset.exclude(**{field: ''}).values_list(field, flat=True):
        for prefix in prefixes:
            if value.startswith(prefix):
                seq = _trailing_sequence(value)
                if seq is not None:
                    max_seq = max(max_seq, seq)
                break
    return max_seq


def next_sequential_document_number(
    *,
    prefix: str,
    model: type[models.Model],
    field: str = 'invoice_number',
    seq_width: int = 4,
    max_attempts: int = 200,
) -> str:
    """
    Allocate a short unique document number.

    Format: {prefix}{YY}-{sequence}
    Examples: S26-0001, P26-0042
    """
    if len(prefix) != 1:
        raise ValueError('prefix must be a single character (S, P, or T)')

    year = timezone.now().year
    yy = year % 100
    head = f'{prefix}{yy:02d}-'

    legacy_builders = _LEGACY_PREFIXES.get(prefix, ())
    legacy_prefixes = tuple(builder(year) for builder in legacy_builders)
    prefixes = (head, *legacy_prefixes)

    max_seq = _max_sequence_for_prefixes(model.objects.all(), field, prefixes)

    for offset in range(1, max_attempts + 1):
        candidate = f'{head}{max_seq + offset:0{seq_width}d}'
        if not model.objects.filter(**{field: candidate}).exists():
            return candidate

    raise RuntimeError(f'Could not allocate unique {field} with prefix {head}')


def allocate_sale_invoice_number() -> str:
    from api.models.data.sales import Sales

    return next_sequential_document_number(prefix='S', model=Sales)


def allocate_raw_material_purchase_invoice_number() -> str:
    from api.models.data.raw_materials import RawMaterialPurchase

    return next_sequential_document_number(prefix='R', model=RawMaterialPurchase)


def allocate_raw_material_process_number() -> str:
    from api.models.data.raw_material_process import RawMaterialProcess

    return next_sequential_document_number(
        prefix='M',
        model=RawMaterialProcess,
        field='process_number',
    )


def allocate_equipment_serial_number() -> str:
    """Allocate a unique equipment serial / asset label: E26-0001."""
    from api.models.data.equipment import Equipment

    return next_sequential_document_number(
        prefix='E',
        model=Equipment,
        field='serial_number',
    )


def allocate_stock_transfer_number() -> str:
    """Allocate a unique stock transfer number: T26-0001."""
    from api.models.data.stock_transfer import StockTransfer

    return next_sequential_document_number(
        prefix='T',
        model=StockTransfer,
        field='transfer_number',
    )


def allocate_batch_number(purchase_invoice: str | None = None, item_seq: int | None = None) -> str:
    """Allocate a unique batch number: B{YY}-{seq:04d}  e.g. B26-0001."""
    from api.models.data.inventory_batch import InventoryBatch

    return next_sequential_document_number(
        prefix='B',
        model=InventoryBatch,
        field='batch_number',
    )
