#!/usr/bin/env python3
"""
Union-type CSV exporter: JSON field values that alternate between
string and array across records.

Policy:
  - If the declared field value is a string, write it to <field>_value
    and set <field>_kind = "string", <field>_count = 1.
  - If the value is an array, join elements with a record-level delimiter
    (pipe |), write the joined string to <field>_value, set
    <field>_kind = "array", <field>_count = len(array).
  - The raw JSON spelling of the value is preserved in <field>_json
    so a reader can reconstruct the original shape exactly.

This is a local recipe executed on 2026-10-31 with Python 3.13.14.
"""

import json
import csv
import hashlib
import sys
from pathlib import Path

UNION_FIELDS = ["tags"]
BASE_FIELDS = ["id"]
SCHEMA = (
    BASE_FIELDS
    + [f"{f}_kind" for f in UNION_FIELDS]
    + [f"{f}_count" for f in UNION_FIELDS]
    + [f"{f}_value" for f in UNION_FIELDS]
    + [f"{f}_json" for f in UNION_FIELDS]
)
ARRAY_DELIM = "|"


def export_union(source_path, csv_path):
    with open(source_path, "r", encoding="utf-8") as f:
        raw_text = f.read()
    records = json.loads(raw_text)

    rows = []
    for rec in records:
        row = {col: "" for col in SCHEMA}
        row["id"] = rec.get("id", "")
        for field in UNION_FIELDS:
            val = rec.get(field, "")
            row[f"{field}_json"] = json.dumps(val, ensure_ascii=False)
            if isinstance(val, str):
                row[f"{field}_kind"] = "string"
                row[f"{field}_count"] = 1
                row[f"{field}_value"] = val
            elif isinstance(val, list):
                row[f"{field}_kind"] = "array"
                row[f"{field}_count"] = len(val)
                row[f"{field}_value"] = ARRAY_DELIM.join(
                    str(e) for e in val
                )
            else:
                row[f"{field}_kind"] = "other"
                row[f"{field}_count"] = 0
                row[f"{field}_value"] = str(val)
        rows.append(row)

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

    return rows, raw_text


def read_back(csv_path):
    with open(csv_path, "r", encoding="utf-8", newline="") as f:
        reader = csv.DictReader(f)
        return list(reader)


def verify(source_path, csv_path):
    import subprocess
    rows, raw_text = export_union(source_path, csv_path)
    readback = read_back(csv_path)

    source_records = json.loads(raw_text)
    checks = []
    for i, (src, out) in enumerate(zip(source_records, readback)):
        src_val = src.get("tags", "")
        if isinstance(src_val, str):
            expected_kind = "string"
            expected_count = 1
            expected_value = src_val
        elif isinstance(src_val, list):
            expected_kind = "array"
            expected_count = len(src_val)
            expected_value = "|".join(str(e) for e in src_val)
        else:
            expected_kind = "other"
            expected_count = 0
            expected_value = str(src_val)

        expected_json = json.dumps(src_val, ensure_ascii=False)

        checks.append({
            "row": i,
            "id": src.get("id", ""),
            "tags_kind_match": out["tags_kind"] == expected_kind,
            "tags_count_match": int(out["tags_count"]) == expected_count,
            "tags_value_match": out["tags_value"] == expected_value,
            "tags_json_match": out["tags_json"] == expected_json,
        })

    src_sha = hashlib.sha256(raw_text.encode("utf-8")).hexdigest()
    csv_bytes = Path(csv_path).read_bytes()
    csv_sha = hashlib.sha256(csv_bytes).hexdigest()

    all_pass = all(
        c["tags_kind_match"]
        and c["tags_count_match"]
        and c["tags_value_match"]
        and c["tags_json_match"]
        for c in checks
    )

    return {
        "python_version": sys.version,
        "source_sha256": src_sha,
        "source_bytes": len(raw_text.encode("utf-8")),
        "csv_sha256": csv_sha,
        "csv_bytes": len(csv_bytes),
        "csv_path": str(csv_path),
        "row_count": len(readback),
        "column_count": len(SCHEMA),
        "all_checks_passed": all_pass,
        "checks": checks,
    }


if __name__ == "__main__":
    base = Path(__file__).parent
    src = base / "union-type-fixture.json"
    csv_out = base / "union-type-output.csv"
    result = verify(src, csv_out)
    print(json.dumps(result, indent=2))
