import argparse, csv, json
from pathlib import Path

def reject_constant(token):
    raise ValueError("Non-JSON constant: " + token)

def unique_keys(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError("Duplicate key: " + key)
        result[key] = value
    return result

def decode(raw):
    return json.loads(raw, parse_constant=reject_constant,
                      object_pairs_hook=unique_keys)

def decode_utf16(raw, encoding):
    if raw.startswith((b"\xff\xfe\x00\x00", b"\x00\x00\xfe\xff")):
        raise ValueError("UTF-32 is outside this UTF-16 recipe")
    mark = None
    if raw.startswith(b"\xff\xfe"):
        mark = "utf-16-le"
    elif raw.startswith(b"\xfe\xff"):
        mark = "utf-16-be"
    if encoding == "utf-16":
        if mark is None:
            raise ValueError("Missing UTF-16 BOM; declare byte order")
        codec = mark
    else:
        codec = encoding
        if mark is not None and mark != codec:
            raise ValueError("BOM conflicts with declared byte order")
    payload = raw[2:] if mark is not None else raw
    return payload.decode(codec, errors="strict")

def export(source, target, encoding="utf-16"):
    source, target = Path(source), Path(target)
    if source.resolve() == target.resolve():
        raise ValueError("Source and destination must differ")
    if source.stat().st_size > 1_000_000:
        raise ValueError("Demo byte cap exceeded")
    raw = source.read_bytes()
    data = decode(decode_utf16(raw, encoding))
    if not isinstance(data, list):
        raise ValueError("Expected a records array")
    for row in data:
        if not isinstance(row, dict) or set(row) != {"id", "text"}:
            raise ValueError("Expected exact id/text objects")
        if not all(isinstance(row[k], str) for k in ("id", "text")):
            raise ValueError("id and text must be strings")
    with target.open("x", encoding="utf-8", newline="") as f:
        writer = csv.writer(f, lineterminator="\n")
        writer.writerow(["id", "text"])
        writer.writerows((row["id"], row["text"]) for row in data)

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    p.add_argument("source")
    p.add_argument("target")
    p.add_argument("--input-encoding", choices=["utf-16", "utf-16-le", "utf-16-be"], default="utf-16")
    args = p.parse_args()
    try:
        export(args.source, args.target, args.input_encoding)
    except (ValueError, OSError, RecursionError) as e:
        p.exit(1, str(e) + "\n")
