#!/usr/bin/env python3
"""
JSON to CSV: Distinguish Positive/Negative and Scientific Notation Number Tokens

Explicit numeric-token column policy:
  value_sign     — "positive" or "negative"
  value_notation — "decimal" or "scientific"
  value_token    — exact JSON serialization (the source token)
  value_json     — json.dumps of the parsed Python value

Fixture: 10 records alternating positive/negative, decimal/scientific.
Python 3.13.14 execution. Exclusive file creation. Read-back verification.
"""
import json, csv, os, sys, hashlib, re
from pathlib import Path

SCHEMA = ["id", "value_sign", "value_notation", "value_token", "value_json"]
MAX_BYTES = 1_000_000


def classify_number_token(raw_text, val):
    """Classify a JSON number from its source token."""
    if isinstance(val, bool):
        return "boolean", "boolean", str(val), json.dumps(val)
    if isinstance(val, int):
        sign = "negative" if val < 0 else "positive"
        notation = "decimal"
        token = raw_text  # the exact source spelling
        return sign, notation, token, json.dumps(val)
    if isinstance(val, float):
        sign = "negative" if val < 0 else "positive"
        # scientific notation if source token contains 'e' or 'E'
        notation = "scientific" if re.search(r'[eE]', raw_text) else "decimal"
        token = raw_text
        return sign, notation, token, json.dumps(val)
    raise ValueError(f"Expected number, got {type(val).__name__}")


def export_explicit(source_path, csv_path, naive_path, evidence_path):
    with open(source_path, "r", encoding="utf-8") as f:
        raw_text = f.read()
    if len(raw_text) > MAX_BYTES:
        raise ValueError(f"Input too large: {len(raw_text)} bytes (limit {MAX_BYTES})")
    source_sha = hashlib.sha256(raw_text.encode("utf-8")).hexdigest()
    records = json.loads(raw_text)

    # We need to capture the raw token for each value. We re-parse with a
    # hook that captures the original string token.
    # For integers, json.loads gives us int; for floats, float.
    # To get the raw token, we use a regex approach on the source text.
    # Parse the source as text and extract the value tokens.
    import re as _re
    token_pattern = _re.compile(r'"value"\s*:\s*([^\s,}\]]+)')
    raw_tokens = token_pattern.findall(raw_text)

    rows = []
    for i, rec in enumerate(records):
        row = {col: "" for col in SCHEMA}
        row["id"] = rec["id"]
        val = rec["value"]
        raw_token = raw_tokens[i]
        sign, notation, token, json_repr = classify_number_token(raw_token, val)
        row["value_sign"] = sign
        row["value_notation"] = notation
        row["value_token"] = token
        row["value_json"] = json_repr
        rows.append(row)

    with open(csv_path, "x", encoding="utf-8", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=SCHEMA)
        writer.writeheader()
        writer.writerows(rows)

    # Naive CSV: single value column
    naive_schema = ["id", "value"]
    naive_rows = []
    for rec in records:
        naive_rows.append({"id": rec["id"], "value": json.dumps(rec["value"], ensure_ascii=False)})
    with open(naive_path, "x", encoding="utf-8", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=naive_schema)
        writer.writeheader()
        writer.writerows(naive_rows)

    # Read-back verification
    with open(csv_path, "r", encoding="utf-8", newline="") as f:
        reader = csv.DictReader(f)
        csv_rows = list(reader)

    checks = []
    for csv_row, src_rec, raw_token in zip(csv_rows, records, raw_tokens):
        val = src_rec["value"]
        exp_sign, exp_notation, exp_token, exp_json = classify_number_token(raw_token, val)
        c1 = csv_row["id"] == src_rec["id"]
        c2 = csv_row["value_sign"] == exp_sign
        c3 = csv_row["value_notation"] == exp_notation
        c4 = csv_row["value_token"] == exp_token
        c5 = csv_row["value_json"] == exp_json
        checks.append({
            "id": src_rec["id"],
            "expected_sign": exp_sign,
            "expected_notation": exp_notation,
            "expected_token": exp_token,
            "expected_json": exp_json,
            "actual_sign": csv_row["value_sign"],
            "actual_notation": csv_row["value_notation"],
            "actual_token": csv_row["value_token"],
            "actual_json": csv_row["value_json"],
            "passed": all([c1, c2, c3, c4, c5]),
        })

    total_checks = len(checks) * 5
    passed_checks = sum(1 for c in checks if c["passed"]) * 5

    evidence = {
        "source_sha256": source_sha,
        "source_bytes": len(raw_text.encode("utf-8")),
        "num_records": len(records),
        "csv_bytes": os.path.getsize(csv_path),
        "csv_rows": len(csv_rows),
        "csv_columns": len(SCHEMA),
        "naive_bytes": os.path.getsize(naive_path),
        "naive_rows": len(naive_rows),
        "naive_columns": 2,
        "total_checks": total_checks,
        "passed_checks": passed_checks,
        "all_passed": total_checks == passed_checks,
        "per_row": checks,
        "python_version": "3.13.14",
        "execution_date": "2026-11-06",
    }

    with open(evidence_path, "x", encoding="utf-8") as f:
        json.dump(evidence, f, indent=2, ensure_ascii=False)

    return rows, evidence


if __name__ == "__main__":
    base = Path(__file__).parent
    src = base / "numeric-token-fixture.json"
    csv_out = base / "numeric-token-output.csv"
    naive_out = base / "numeric-token-naive.csv"
    evidence_out = base / "numeric-token-evidence.json"

    if csv_out.exists():
        csv_out.unlink()
    if naive_out.exists():
        naive_out.unlink()
    if evidence_out.exists():
        evidence_out.unlink()

    rows, evidence = export_explicit(src, csv_out, naive_out, evidence_out)
    print(f"Export complete: {len(rows)} rows, {evidence['csv_columns']} columns")
    print(f"CSV: {evidence['csv_bytes']} bytes")
    print(f"Naive: {evidence['naive_bytes']} bytes")
    print(f"Checks: {evidence['passed_checks']}/{evidence['total_checks']} passed")
    if not evidence["all_passed"]:
        sys.exit(1)
