import re

LITERALS = {
    "today": "TODAY",
    "yesterday": "YESTERDAY",
    "tomorrow": "TOMORROW",
    "this week": "THIS_WEEK",
    "last week": "LAST_WEEK",
    "next week": "NEXT_WEEK",
    "this month": "THIS_MONTH",
    "last month": "LAST_MONTH",
    "next month": "NEXT_MONTH",
    "this quarter": "THIS_QUARTER",
    "last quarter": "LAST_QUARTER",
    "next quarter": "NEXT_QUARTER",
    "this year": "THIS_YEAR",
    "last year": "LAST_YEAR",
    "next year": "NEXT_YEAR",
    "this fiscal year": "THIS_FISCAL_YEAR",
    "last fiscal year": "LAST_FISCAL_YEAR",
    "next fiscal year": "NEXT_FISCAL_YEAR",
    "this fiscal quarter": "THIS_FISCAL_QUARTER",
    "last fiscal quarter": "LAST_FISCAL_QUARTER",
    "next fiscal quarter": "NEXT_FISCAL_QUARTER",
    "last 90 days": "LAST_90_DAYS",
}


def to_literal(phrase: str) -> str | None:
    """Translate friendly date phrases to Salesforce date literals.

    Supports:
    - Static literals: "today", "this quarter", "last fiscal quarter", etc.
    - N-based days: "last 30 days", "next 7 days"
    - N-based weeks: "last 4 weeks", "next 2 weeks"
    - N-based months: "last 3 months", "next 6 months"
    - N-based quarters: "last 2 quarters", "next 1 quarter"
    - N-based years: "last 2 years", "next 1 year"
    - N-based fiscal quarters: "last 2 fiscal quarters", "next 4 fiscal quarters"
    - N-based fiscal years: "last 2 fiscal years", "next 1 fiscal year"
    """
    if not phrase:
        return None
    normalized = phrase.strip().lower()

    # Check static literals first
    if normalized in LITERALS:
        return LITERALS[normalized]

    # N-based patterns: "last/next N <unit>"
    # Order matters - check longer patterns (fiscal quarters) before shorter (quarters)

    # Fiscal quarters: "last 2 fiscal quarters"
    match = re.match(r"(last|next)\s+(\d+)\s+fiscal\s+quarters?", normalized)
    if match:
        prefix = "LAST" if match.group(1) == "last" else "NEXT"
        return f"{prefix}_N_FISCAL_QUARTERS:{match.group(2)}"

    # Fiscal years: "last 2 fiscal years"
    match = re.match(r"(last|next)\s+(\d+)\s+fiscal\s+years?", normalized)
    if match:
        prefix = "LAST" if match.group(1) == "last" else "NEXT"
        return f"{prefix}_N_FISCAL_YEARS:{match.group(2)}"

    # Days: "last 30 days", "next 7 days"
    match = re.match(r"(last|next)\s+(\d+)\s+days?", normalized)
    if match:
        prefix = "LAST" if match.group(1) == "last" else "NEXT"
        return f"{prefix}_N_DAYS:{match.group(2)}"

    # Weeks: "last 4 weeks", "next 2 weeks"
    match = re.match(r"(last|next)\s+(\d+)\s+weeks?", normalized)
    if match:
        prefix = "LAST" if match.group(1) == "last" else "NEXT"
        return f"{prefix}_N_WEEKS:{match.group(2)}"

    # Months: "last 3 months", "next 6 months"
    match = re.match(r"(last|next)\s+(\d+)\s+months?", normalized)
    if match:
        prefix = "LAST" if match.group(1) == "last" else "NEXT"
        return f"{prefix}_N_MONTHS:{match.group(2)}"

    # Quarters: "last 2 quarters", "next 1 quarter"
    match = re.match(r"(last|next)\s+(\d+)\s+quarters?", normalized)
    if match:
        prefix = "LAST" if match.group(1) == "last" else "NEXT"
        return f"{prefix}_N_QUARTERS:{match.group(2)}"

    # Years: "last 2 years", "next 1 year"
    match = re.match(r"(last|next)\s+(\d+)\s+years?", normalized)
    if match:
        prefix = "LAST" if match.group(1) == "last" else "NEXT"
        return f"{prefix}_N_YEARS:{match.group(2)}"

    return None
