from __future__ import annotations

from dataclasses import dataclass


@dataclass(frozen=True)
class DateFormatField:
    kind: str


@dataclass(frozen=True)
class DateFormatLiteral:
    text: str


DateFormatPart = DateFormatField | DateFormatLiteral

_SEMANTIC_FIELD_KIND = {
    ("y", 2): "year_2",
    ("y", 4): "year_4",
    ("Y", 1): "year_4",
    ("m", 1): "month_unpadded",
    ("m", 2): "month_padded",
    ("d", 1): "day_unpadded",
    ("d", 2): "day_padded",
    ("H", 1): "hour24_unpadded",
    ("H", 2): "hour24_padded",
    ("M", 1): "minute_unpadded",
    ("M", 2): "minute_padded",
    ("S", 1): "second_unpadded",
    ("S", 2): "second_padded",
    ("s", 1): "millisecond",
    ("e", 1): "weekday_abbr",
    ("E", 1): "weekday_full",
    ("u", 1): "month_abbr",
    ("U", 1): "month_full",
    ("z", 1): "tz_offset",
    ("Z", 1): "tz_name",
    ("I", 1): "hour12_unpadded",
    ("I", 2): "hour12_padded",
    ("p", 1): "ampm",
}
_TOKEN_SYMBOLS = frozenset(symbol for symbol, _ in _SEMANTIC_FIELD_KIND)


def _field_kind(symbol: str, width: int, fmt: str) -> str:
    # Julia-style date tokens in this project use a fixed small set.
    # Keep strict errors for unexpected widths rather than inventing behavior.
    key = (symbol, width)
    if key in _SEMANTIC_FIELD_KIND:
        return _SEMANTIC_FIELD_KIND[key]
    raise ValueError(f"Unsupported date format token {symbol * width!r} in {fmt!r}")


def parse_julia_datetime_format(fmt: str) -> list[DateFormatPart]:
    parts: list[DateFormatPart] = []
    literal: list[str] = []

    def flush_literal() -> None:
        if literal:
            parts.append(DateFormatLiteral("".join(literal)))
            literal.clear()

    i = 0
    while i < len(fmt):
        ch = fmt[i]
        if ch == "\\":
            if i + 1 >= len(fmt):
                raise ValueError(f"Invalid date format: dangling escape in {fmt!r}")
            nxt = fmt[i + 1]
            if nxt == "\\":
                # Preserve existing escaped-backslash semantics:
                # "\\x" means literal "\" followed by literal "x".
                if i + 2 >= len(fmt):
                    raise ValueError(
                        f"Invalid date format: escaped backslash must be followed by a literal char in {fmt!r}"
                    )
                literal.append("\\")
                literal.append(fmt[i + 2])
                i += 3
                continue
            literal.append(nxt)
            i += 2
            continue

        if ch.isalpha() and ch in _TOKEN_SYMBOLS:
            flush_literal()
            j = i + 1
            while j < len(fmt) and fmt[j] == ch:
                j += 1
            parts.append(DateFormatField(_field_kind(ch, j - i, fmt)))
            i = j
            continue

        literal.append(ch)
        i += 1

    flush_literal()
    return parts
