"""Local cost illustration, using public-preview prices checked 2026-09-23.

No cloud calls. This is not a bill or a quote. See the accompanying article.
"""
import argparse
import json
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP


def nonnegative(value):
    try:
        number = Decimal(value)
    except InvalidOperation as error:
        raise argparse.ArgumentTypeError("finite nonnegative number required") from error
    if not number.is_finite() or number < 0:
        raise argparse.ArgumentTypeError("finite nonnegative number required")
    return number


def call_count(value):
    try:
        number = int(value)
    except ValueError as error:
        raise argparse.ArgumentTypeError("nonnegative integer required") from error
    if number < 0:
        raise argparse.ArgumentTypeError("nonnegative integer required")
    return number


def estimate(active_hours, allocated_vcpus, peak_memory_gb,
             storage_gib, storage_months, standard_tool_calls):
    # Temporary public-preview CPU rule, NOT measured CPU consumption.
    items = {
        "cpu_usd": active_hours * allocated_vcpus * Decimal("0.25") * Decimal("0.044"),
        "memory_usd": active_hours * peak_memory_gb * Decimal("0.0095"),
        "workspace_storage_usd": storage_gib * storage_months * Decimal("0.05"),
        "standard_tool_calls_usd": Decimal(standard_tool_calls) * Decimal("0.10") / 1000,
    }
    items["illustrative_subtotal_usd"] = sum(items.values(), Decimal(0))
    return {
        "price_checked_at": "2026-09-23",
        "cpu_rule": "preview: 25% of allocated vCPUs while unpaused",
        "assumptions": {
            "unpaused_hours": str(active_hours),
            "allocated_vcpus": str(allocated_vcpus),
            "constant_peak_memory_gb": str(peak_memory_gb),
            "constant_workspace_gib": str(storage_gib),
            "storage_months": str(storage_months),
            "standard_tool_calls": standard_tool_calls,
        },
        "costs": {key: str(value.quantize(Decimal("0.0001"), rounding=ROUND_HALF_UP))
                  for key, value in items.items()},
        "excluded": ["model inference", "internet egress", "snapshots and checkpoints",
                     "custom images", "paid search/partner tools", "tax", "exchange fees"],
        "note": "Illustration only; not usage measurement or an invoice prediction.",
    }


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--active-hours", type=nonnegative, default=Decimal("10"))
    parser.add_argument("--vcpus", type=nonnegative, default=Decimal("2"))
    parser.add_argument("--peak-memory-gb", type=nonnegative, default=Decimal("4"))
    parser.add_argument("--storage-gib", type=nonnegative, default=Decimal("2"))
    parser.add_argument("--storage-months", type=nonnegative, default=Decimal("1"))
    parser.add_argument("--standard-tool-calls", type=call_count, default=600)
    args = parser.parse_args()
    result = estimate(args.active_hours, args.vcpus, args.peak_memory_gb,
                      args.storage_gib, args.storage_months, args.standard_tool_calls)
    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    main()
