"""Command line: python analyze.py data.csv [--target COL | --no-target] [--compare test.csv]
                                         [--json report.json] [--markdown report.md]
                                         [--script clean.py] [--fix cleaned.csv] [--today YYYY-MM-DD]
"""
import argparse
import json
import os
import sys

import doctor
from doctor.jscompat import js_str, to_fixed


def _json_safe(v):
    """Like JSON.stringify: NaN and Infinity become null."""
    if isinstance(v, float) and (v != v or v in (float("inf"), float("-inf"))):
        return None
    if isinstance(v, dict):
        return {k: _json_safe(x) for k, x in v.items()}
    if isinstance(v, (list, tuple)):
        return [_json_safe(x) for x in v]
    return v


def main(argv=None):
    ap = argparse.ArgumentParser(description="Check a CSV for the data problems that quietly ruin a model.")
    ap.add_argument("csv", help="the CSV file to check")
    g = ap.add_mutually_exclusive_group()
    g.add_argument("--target", help="column to predict (default: guessed from the column names)")
    g.add_argument("--no-target", action="store_true", help="don't use a target column")
    ap.add_argument("--compare", metavar="TEST_CSV", help="a second file (e.g. the test set) to compare against")
    ap.add_argument("--json", metavar="FILE", help="write the full report as JSON")
    ap.add_argument("--markdown", metavar="FILE", help="write a Markdown report")
    ap.add_argument("--script", metavar="FILE", help="write a pandas cleaning script")
    ap.add_argument("--fix", metavar="FILE", help="write a cleaned copy of the CSV")
    ap.add_argument("--today", metavar="YYYY-MM-DD", help="flag dates after this day as in the future")
    args = ap.parse_args(argv)

    target = None if args.no_target else (args.target if args.target is not None else doctor.AUTO)
    table = doctor.read_csv(args.csv)
    compare = doctor.read_csv(args.compare) if args.compare else None
    if args.target and args.target not in table.columns:
        print(f"warning: no column named {args.target!r}; running without a target", file=sys.stderr)
    report = doctor.analyze(table, target=target, compare=compare, today=args.today)
    name = os.path.basename(args.csv)

    print()
    print("=" * 50)
    print("DATASET DOCTOR")
    print("=" * 50)

    print()
    print(f"Health score: {report['score']['overall']}/100")
    print(f"Rows: {report['rows']}")
    print(f"Columns: {len(report['columns'])}")
    t = report["target"]
    print(f"Target: {t['column']} ({t.get('kind')})" if t else "Target: none")
    lost = [(c, p) for c, p in report["score"]["penalties"].items() if p]
    if lost:
        print("Penalties by category: " + ", ".join(f"{c} {js_str(round(p, 1))}" for c, p in lost))

    print()
    print("Issues")
    print("-" * 50)

    if not report["issues"]:
        print("No major issues detected.")

    for issue in report["issues"]:
        print(f"[{issue['severity'].upper()}] {issue['title']}")

    if report["featureStrength"]:
        metric = report["featureStrength"][0]["metric"]
        print()
        print(f"Single-feature strength ({metric}, out-of-fold)")
        print("-" * 50)
        width = max(len(s["column"]) for s in report["featureStrength"])
        for s in report["featureStrength"]:
            mark = "  <- suspicious" if s.get("flag") else ""
            print(f"{s['column']:<{width}}  {to_fixed(s['score'], 3)}{mark}")

    if args.json:
        with open(args.json, "w", encoding="utf-8") as f:
            json.dump(_json_safe({k: v for k, v in report.items() if not k.startswith("_")}), f, indent=1, ensure_ascii=False)
    if args.markdown:
        with open(args.markdown, "w", encoding="utf-8") as f:
            f.write(doctor.report_markdown(report, filename=name))
    if args.script:
        with open(args.script, "w", encoding="utf-8") as f:
            f.write(doctor.cleaning_script(report, filename=name))
    if args.fix:
        cleaned = doctor.apply_fixes(table, report)
        with open(args.fix, "w", encoding="utf-8", newline="") as f:
            f.write(doctor.to_csv(cleaned))
        print()
        print("Cleaned file: " + args.fix)
        for line in cleaned.log:
            print("  - " + line)
    written = [p for p in (args.json, args.markdown, args.script) if p]
    if written:
        print()
        print("Wrote " + ", ".join(written))


if __name__ == "__main__":
    main()
