"""THE VERBATIM ANCHOR — Genesys Cloud tokens model, as published.

Transcribed from
https://help.genesys.cloud/articles/genesys-cloud-tokens-model/
**last updated 2026-07-12**. Feature names and rate strings below are the
article's own wording, character for character.

VERBATIM — DO NOT EDIT. A vendor republication is a deliberate
**re-anchoring**, not a patch (docs/Calculator_Pattern_V1-00.md):

    1. diff the published table against this file
    2. update the meters AND bump RATE_CARD_SOURCE_DATE in the same edit
    3. update the pins in tests/test_rate_card.py in the same commit
    4. re-execute the notebook
    5. report the cost moves honestly
    6. Show-first — the user sees the rate diff before it lands

Never partially re-anchor; never bump the date without the pins.

Negotiated or contracted values NEVER land here. They are the overlay, and
they live in the notebook's ``engagement-data`` cell — this file is the
vendor's record, not the client's deal.
"""

from __future__ import annotations

from .meters import LicenceModel, Meter, MeterBasis, Tier

RATE_CARD_SOURCE: str = "https://help.genesys.cloud/articles/genesys-cloud-tokens-model/"
RATE_CARD_SOURCE_DATE: str = "2026-07-12"

# Every meter below is published on the same page on the same date, so the
# source pair is spelled out once here and passed explicitly. Explicit beats
# a splat: this file is diffed against the article by eye.
_URL = RATE_CARD_SOURCE
_DATE = RATE_CARD_SOURCE_DATE


#: The published meter table, verbatim. Twenty rows, in the article's order.
METERS_VERBATIM: tuple[Meter, ...] = (
    Meter(
        key="bots_voice",
        feature="Bots (Voice)",
        published_rate="17 minutes per token",
        basis=MeterBasis.VOICE_MINUTES,
        rate=1.0 / 17.0,
        tier=Tier.BOT,
        unit_label="bot minutes",
        note=(
            "Genesys rounds up each call to the next 15-second increment "
            "(clarified 2026-07-12)."
        ),
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="bots_digital",
        feature="Bots (Digital)",
        published_rate="51 sessions per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 51.0,
        tier=Tier.BOT,
        unit_label="sessions",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="virtual_agent",
        feature="Virtual Agent",
        published_rate="0.5 tokens per Virtual Agent interaction",
        basis=MeterBasis.TOKENS_PER_UNIT,
        rate=0.5,
        tier=Tier.VIRTUAL_AGENT,
        unit_label="interactions",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="agentic_virtual_agent",
        feature="Agentic Virtual Agent",
        published_rate="1.2 tokens per interaction",
        basis=MeterBasis.TOKENS_PER_UNIT,
        rate=1.2,
        tier=Tier.AGENTIC_VIRTUAL_AGENT,
        unit_label="interactions",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="agent_copilot_named",
        feature="Agent Copilot [named]",
        published_rate="40 tokens per user",
        basis=MeterBasis.PER_USER_PER_MONTH,
        per_user_named=40.0,
        per_user_concurrent=60.0,
        unit_label="users",
        note="Enabling Copilot makes Supervisor summaries and insights free.",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="agent_copilot_concurrent",
        feature="Agent Copilot [concurrent]",
        published_rate="60 tokens per user",
        basis=MeterBasis.PER_USER_PER_MONTH,
        per_user_named=40.0,
        per_user_concurrent=60.0,
        unit_label="users",
        note="The concurrent-licence face of the same meter.",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="ai_scoring",
        feature="AI Scoring",
        published_rate="20 evaluations per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 20.0,
        unit_label="evaluations",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="ai_translate",
        feature="AI Translate",
        published_rate="2 translations per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 2.0,
        unit_label="translations",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="ai_summary_and_insights",
        feature="AI Summary and Insights",
        published_rate="50 summaries/insights per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 50.0,
        unit_label="summaries",
        note=(
            "Free when Agent Copilot is enabled — see "
            "COPILOT_COVERS_SUMMARY_RULE."
        ),
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="apple_messages_for_business",
        feature="Apple Messages for Business",
        published_rate="400 inbound or outbound messages per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 400.0,
        unit_label="messages",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="facebook_messenger",
        feature="Facebook Messenger",
        published_rate="400 messages per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 400.0,
        unit_label="messages",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="instagram_direct_messaging",
        feature="Instagram Direct Messaging",
        published_rate="400 messages per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 400.0,
        unit_label="messages",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="whatsapp_messaging",
        feature="WhatsApp Messaging",
        published_rate="400 messages per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 400.0,
        unit_label="messages",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="x_direct_messaging",
        feature="X Direct Messaging",
        published_rate="400 messages per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 400.0,
        unit_label="messages",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="genesys_cloud_social",
        feature="Genesys Cloud Social",
        published_rate="400 social post ingestions per channel per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 400.0,
        unit_label="post ingestions",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="social_post_responses",
        feature="Social Post Responses",
        published_rate="400 outbound messages per channel per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 400.0,
        unit_label="outbound messages",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="predictive_routing",
        feature="Predictive Routing",
        published_rate="17 routes per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 17.0,
        unit_label="routes",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="speech_and_text_analytics_named",
        feature="Speech and Text Analytics [named]",
        published_rate="30 tokens per user",
        basis=MeterBasis.PER_USER_PER_MONTH,
        per_user_named=30.0,
        per_user_concurrent=45.0,
        unit_label="users",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="speech_and_text_analytics_concurrent",
        feature="Speech and Text Analytics [concurrent]",
        published_rate="45 tokens per user",
        basis=MeterBasis.PER_USER_PER_MONTH,
        per_user_named=30.0,
        per_user_concurrent=45.0,
        unit_label="users",
        note="The concurrent-licence face of the same meter.",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="genesys_cloud_copilot",
        feature="Genesys Cloud Copilot",
        published_rate="20 AI actions per token",
        basis=MeterBasis.UNITS_PER_TOKEN,
        rate=1.0 / 20.0,
        unit_label="AI actions",
        note="Genesys Cloud knowledge queries are not charged.",
        source_url=_URL,
        source_date=_DATE,
    ),
)


#: Published as included at no token cost. Shown on stage as explicit $0
#: lines — a zero the vendor put in writing is a finding, not an omission.
ZERO_RATED_VERBATIM: tuple[Meter, ...] = (
    Meter(
        key="predictive_engagement",
        feature="Predictive Engagement",
        published_rate="No charge for token usage",
        basis=MeterBasis.ZERO_RATED,
        unit_label="interactions",
        source_url=_URL,
        source_date=_DATE,
    ),
    Meter(
        key="knowledge_queries",
        feature="Genesys Cloud knowledge queries",
        published_rate="no charge for Genesys Cloud knowledge queries",
        basis=MeterBasis.ZERO_RATED,
        unit_label="queries",
        source_url=_URL,
        source_date=_DATE,
    ),
)


#: "Named organizations receive 250 tokens; concurrent organizations receive
#: 350 tokens" per month.
FREE_TOKENS_PER_MONTH: dict[LicenceModel, int] = {
    LicenceModel.NAMED: 250,
    LicenceModel.CONCURRENT: 350,
}

#: "These tokens renew each month and do not carry over to future months."
ALLOWANCE_CARRIES_OVER: bool = False

#: "Genesys rounds up each call to the next 15-second increment."
#: Clarified in the 2026-07-12 revision. Applied PER CALL, then summed.
VOICE_BOT_ROUNDUP_SECONDS: int = 15

#: The published highest-tier rule, verbatim. Renders on stage.
HIGHEST_TIER_RULE: str = (
    "In cases where an interaction uses multiple AI resources, such as bot "
    "flows, virtual agents, and agentic virtual agents, Genesys bases charges "
    "on the highest tier (price) resource that Genesys Cloud uses during the "
    "interaction."
)

#: The published Copilot exclusion, verbatim. Renders on stage.
COPILOT_COVERS_SUMMARY_RULE: str = (
    "if you enable Agent Copilot simultaneously, then Supervisor Copilot "
    "summaries and insights do not consume tokens"
)

#: List price per token. The article points to the pricing hub and cites
#: "USD 1.00 to JPY 120 per token by currency".
LIST_PRICE_BY_CURRENCY: dict[str, float] = {"USD": 1.00, "JPY": 120.0}


#: Every meter by key — the consumption table plus the zero-rated lines.
METERS: dict[str, Meter] = {
    m.key: m for m in METERS_VERBATIM + ZERO_RATED_VERBATIM
}


def meter(key: str) -> Meter:
    """Look up a published meter, with a useful error when the key is wrong."""
    try:
        return METERS[key]
    except KeyError:
        raise KeyError(
            f"{key!r} is not a published Genesys meter. Known keys: "
            f"{', '.join(sorted(METERS))}"
        ) from None


def per_user_meter(licence: LicenceModel, family: str) -> Meter:
    """The Copilot / STA meter face matching ``licence``.

    ``family`` is ``"agent_copilot"`` or ``"speech_and_text_analytics"``.
    Both rates live on both faces, so this is presentation sugar — it picks
    the row whose published wording matches the licence being modelled.
    """
    return meter(f"{family}_{licence.value}")


def rate_card_rows() -> list[dict[str, str]]:
    """The published table as display rows, in publication order."""
    return [
        {
            "Feature": m.feature,
            "Published rate": m.published_rate,
            "Confidence": m.confidence.icon,
            "Source": m.source_date or "",
        }
        for m in METERS_VERBATIM + ZERO_RATED_VERBATIM
    ]
