"""
CA Automator — Audit Execution computation engines (the tools from the
"Audit Automators" list NOT already covered by stat_audit's materiality/
sample-size/inherent-control-risk, internal_audit's risk-based planning/
RACM/walkthroughs/findings, or forensic_audit's journal-entry and
related-party detectors).

Pure functions only (no DB access), mirrored line-for-line in
web/audit_execution_engines.js — same discipline as tax_advisory_engines.py.
systematic_sample is the ONE sampling-selection function here, and
deliberately deterministic (interval and start point, not a random-number
generator) so it verifies identically between the Python and JS mirrors —
true random/haphazard/judgmental selection is recorded as the preparer's own
documented choice, never simulated.
"""

R2 = lambda x: round(float(x or 0), 2)


def _n(v, default=0.0):
    if v is None or v == "":
        return default
    try:
        return float(v)
    except (TypeError, ValueError):
        return default


def _safe_div(a, b):
    return (a / b) if b else 0.0


def systematic_sample(population_size, sample_size, start_point=1):
    """Classic systematic sampling: fixed interval = population_size / sample_size, starting at start_point."""
    pop = int(population_size or 0)
    n = int(sample_size or 0)
    start = int(start_point or 1)
    if pop <= 0 or n <= 0:
        return {"population_size": pop, "sample_size": n, "start_point": start, "interval": 0, "selected_positions": []}
    interval = max(1, pop // n)
    positions = []
    pos = start
    while len(positions) < n and pos <= pop:
        positions.append(pos)
        pos += interval
    return {"population_size": pop, "sample_size": n, "start_point": start, "interval": interval,
           "selected_positions": positions, "actual_count": len(positions)}


def test_item_summary(items):
    """Groups aud_test_item rows by area — exception rate, tested value, confirmation-status breakdown."""
    by_area = {}
    for r in items or []:
        area = r.get("area", "Other")
        g = by_area.setdefault(area, {"count": 0, "exceptions": 0, "matched": 0, "open": 0,
                                      "book_total": 0.0, "tested_total": 0.0, "variance_total": 0.0,
                                      "confirmations_sent": 0, "confirmations_received": 0, "confirmations_discrepancy": 0})
        g["count"] += 1
        status = r.get("status", "open")
        if status == "exception":
            g["exceptions"] += 1
        elif status == "matched":
            g["matched"] += 1
        else:
            g["open"] += 1
        book = _n(r.get("book_amount"))
        tested = r.get("tested_amount")
        g["book_total"] += book
        if tested not in (None, ""):
            tested_v = _n(tested)
            g["tested_total"] += tested_v
            g["variance_total"] += (tested_v - book)
        cs = r.get("confirmation_status")
        if cs in ("sent", "received_agreed", "received_discrepancy"):
            g["confirmations_sent"] += 1
        if cs == "received_agreed":
            g["confirmations_received"] += 1
        if cs == "received_discrepancy":
            g["confirmations_discrepancy"] += 1

    areas = {}
    for area, g in by_area.items():
        areas[area] = {
            "count": g["count"], "exceptions": g["exceptions"], "matched": g["matched"], "open": g["open"],
            "exception_rate_pct": R2(_safe_div(g["exceptions"], g["count"]) * 100),
            "book_total": R2(g["book_total"]), "tested_total": R2(g["tested_total"]), "variance_total": R2(g["variance_total"]),
            "confirmations_sent": g["confirmations_sent"], "confirmations_received": g["confirmations_received"],
            "confirmations_discrepancy": g["confirmations_discrepancy"],
        }
    total_items = sum(a["count"] for a in areas.values())
    total_exceptions = sum(a["exceptions"] for a in areas.values())
    return {"areas": areas, "total_items": total_items, "total_exceptions": total_exceptions,
           "overall_exception_rate_pct": R2(_safe_div(total_exceptions, total_items) * 100)}


def analytical_review(procedures):
    """Variance of actual against an expected value; flagged when the variance exceeds the procedure's own threshold."""
    rows = []
    for r in procedures or []:
        current = _n(r.get("current_period_value"))
        expected = r.get("expected_value")
        threshold = _n(r.get("threshold_pct"), 10)
        variance_pct = None
        flagged = False
        if expected not in (None, ""):
            expected_v = _n(expected)
            variance_pct = R2(_safe_div(current - expected_v, expected_v) * 100) if expected_v else None
            if variance_pct is not None:
                flagged = abs(variance_pct) > threshold
        rows.append({"id": r.get("id"), "metric": r.get("metric", ""), "prior_period_value": R2(_n(r.get("prior_period_value"))),
                    "current_period_value": R2(current), "expected_value": R2(_n(expected)) if expected not in (None, "") else None,
                    "threshold_pct": threshold, "variance_pct": variance_pct, "flagged": flagged,
                    "explanation": r.get("explanation", "")})
    flagged_rows = [r for r in rows if r["flagged"]]
    unexplained = [r for r in flagged_rows if not r["explanation"]]
    return {"rows": rows, "flagged_count": len(flagged_rows), "unexplained_flagged_count": len(unexplained)}


def going_concern_summary(indicators):
    """Present-indicator count by category — a planning aid, never itself the going-concern conclusion."""
    by_category = {}
    present_total = 0
    for r in indicators or []:
        cat = r.get("category") or "Other"
        g = by_category.setdefault(cat, {"total": 0, "present": 0})
        g["total"] += 1
        if r.get("present"):
            g["present"] += 1
            present_total += 1
    return {"by_category": {k: {"total": v["total"], "present": v["present"]} for k, v in by_category.items()},
           "present_count": present_total, "total_count": len(indicators or [])}


def checklist_summary(items):
    """Completion % by area — same shape as ipo_engines.readiness_summary's area grouping."""
    by_area = {}
    for c in items or []:
        area = c.get("area", "")
        g = by_area.setdefault(area, {"total": 0, "done": 0})
        g["total"] += 1
        if c.get("status") == "done":
            g["done"] += 1
    return {area: {"total": g["total"], "done": g["done"], "completion_pct": R2(_safe_div(g["done"], g["total"]) * 100)}
           for area, g in by_area.items()}
