#!/usr/bin/env python3
"""Illustrative Odoo AI budget arithmetic. No network or Odoo integration.

One CSV row represents one unique business case. Credits include all attempts.
All defaults and the accompanying ledger are synthetic planning assumptions.
"""
from argparse import ArgumentParser
from csv import DictReader
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
import json
from pathlib import Path


def nonnegative(raw):
    try:
        value = Decimal(str(raw))
    except InvalidOperation as error:
        raise ValueError(f"Invalid number: {raw!r}") from error
    if not value.is_finite() or value < 0:
        raise ValueError(f"Expected a finite nonnegative number: {raw!r}")
    return value


def money(value):
    return str(value.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))


def calculate(path, credit_price, review_hourly_rate, plan_uplift,
              operations, credits_purchased, opening_credits):
    ids = set()
    accepted = attempts = 0
    credits = minutes = rework = Decimal(0)
    with Path(path).open(newline="", encoding="utf-8") as stream:
        reader = DictReader(stream)
        required = {"case_id", "accepted", "attempts", "credits_consumed", "review_minutes", "rework_minutes"}
        if not required.issubset(reader.fieldnames or []):
            raise ValueError("CSV is missing required columns")
        for row in reader:
            case_id = row["case_id"].strip()
            if not case_id or case_id in ids:
                raise ValueError(f"Empty or duplicate case ID: {case_id!r}")
            ids.add(case_id)
            if row["accepted"] not in {"0", "1"}:
                raise ValueError("accepted must be 0 or 1")
            accepted += int(row["accepted"])
            case_attempts = nonnegative(row["attempts"])
            if case_attempts != case_attempts.to_integral_value():
                raise ValueError("attempts must be a whole number")
            attempts += int(case_attempts)
            credits += nonnegative(row["credits_consumed"])
            minutes += nonnegative(row["review_minutes"])
            rework += nonnegative(row["rework_minutes"])
    closing = opening_credits + credits_purchased - credits
    if closing < 0:
        raise ValueError("Consumed credits exceed opening balance plus purchases")
    consumption_cost = credits * credit_price
    review_cost = minutes / 60 * review_hourly_rate
    rework_cost = rework / 60 * review_hourly_rate
    total = consumption_cost + review_cost + rework_cost + plan_uplift + operations
    return {
        "illustrative_only": True,
        "currency": "EUR",
        "cases": len(ids), "accepted_cases": accepted,
        "unresolved_cases": len(ids) - accepted, "attempts": attempts,
        "credits_consumed": str(credits), "review_hours": str(minutes / 60),
        "rework_hours": str(rework / 60), "human_hours": str((minutes + rework) / 60),
        "consumption_cost": money(consumption_cost), "review_cost": money(review_cost),
        "rework_cost": money(rework_cost),
        "plan_uplift": money(plan_uplift), "operations": money(operations),
        "period_cost": money(total),
        "cost_per_accepted_case": money(total / accepted) if accepted else None,
        "credit_purchase_cash": money(credits_purchased * credit_price),
        "closing_credit_balance": str(closing),
        "notes": "Unique accepted cases; all attempts and all case review included. One-time setup, taxes and currency conversion excluded. Null unit cost means no accepted cases, not free processing."
    }


def main():
    parser = ArgumentParser(description=__doc__)
    parser.add_argument("ledger", nargs="?", default=str(Path(__file__).with_name("synthetic_cases.csv")))
    for name, default in [("credit-price", "1"), ("review-hourly-rate", "60"),
                          ("plan-uplift", "300"), ("operations", "180"),
                          ("credits-purchased", "1000"), ("opening-credits", "0")]:
        parser.add_argument("--" + name, default=default, type=nonnegative)
    args = parser.parse_args()
    try:
        result = calculate(args.ledger, args.credit_price, args.review_hourly_rate,
                           args.plan_uplift, args.operations, args.credits_purchased,
                           args.opening_credits)
    except (ValueError, OSError) as error:
        parser.error(str(error))
    print(json.dumps(result, indent=2))


if __name__ == "__main__":
    main()
