#!/usr/bin/env python3
"""Read-only tracking plan audit: plan quality, then drift against observed data.

Usage (run from a scratch folder; SKILL is the installed skill folder):
  python3 "$SKILL/scripts/audit_plan.py" quality --events PLAN_EVENTS.csv
      --properties PLAN_PROPERTIES.csv [--ga4-param-limit 25]
      [--vendor-events FILE] [--vendor-params FILE] [--json]
  python3 "$SKILL/scripts/audit_plan.py" drift --events PLAN_EVENTS.csv
      --properties PLAN_PROPERTIES.csv --observed OBSERVED.csv [--observed MORE.csv]
      [--reference REFERENCE.csv] [--ga4-definitions GA4_DEFINITIONS.csv]
      [--tool ga4,amplitude] [--window-start YYYY-MM-DD --window-end YYYY-MM-DD]
      [--as-of YYYY-MM-DD] [--vendor-events FILE] [--vendor-params FILE]
      [--ga4-param-limit 25] [--mismatch-share 0.01] [--required-fail 0.95]
      [--min-sample 100] [--global-share 0.8] [--dynamic-min 10]
      [--optional-min-rows 1000] [--out DIR] [--json]

Inputs use the columns of the header-only templates in assets/; the example-acme-*
files show filled rows. Headers match case-insensitively and extra columns are
ignored. tracking-plan-builder's sheet tabs work too: source_system stands in for
sources, and a delivery path marked browser companion, via gtm or via gtag counts
as a web source for that tool unless sources already overrides the tool.

quality applies rules Q01 to Q13 (references/plan-quality.md). drift runs Q05, Q07
and Q08 to set the depth, then D01 to D15 (references/drift-rules.md), classifies
every observed name and prints a cross-tool matrix. drift stops with exit code 2
when the plan defines an event or property twice, or when an inventory row is
given twice. --as-of defaults to the earlier of today and 4 days after
--window-end. --ga4-param-limit is 25 for standard GA4 properties and 100 for
Analytics 360. --out writes findings.csv, observed-snapshot.csv and
plan-changes-draft.csv, and refuses any folder inside martech-context/ or inside
the skill folder, symlinks resolved.

Modules, all in this folder:
  audit_plan.py        this entry point and its options
  common.py            constants, helpers, file readers, Plan and Inventory
  plan_quality.py      rules Q01 to Q13 and the plan verdict
  drift.py             drift setup, observed name classes, D01 to D06, the report and --out
  drift_properties.py  D04 keys, D07 to D11, D13, D14 and D15
  drift_counts.py      D12 reference counts and the cross-tool matrix

Standard library only, Python 3.8 or later. Reads local files, makes no network
calls, changes nothing, and prints no property values except enum values and
redaction tokens. Exit codes: 0 no FAIL, 1 at least one FAIL, 2 bad input.
"""
import argparse
import os
import sys

# The modules sit next to this file. Load them from here (also under python3 -I) and never write
# __pycache__ into the installed skill folder.
sys.dont_write_bytecode = True
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))

from common import ASSETS  # noqa: E402
from drift import cmd_drift  # noqa: E402
from plan_quality import cmd_quality  # noqa: E402


def main():
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    sub = parser.add_subparsers(dest="command")
    for name in ("quality", "drift"):
        p = sub.add_parser(name)
        p.add_argument("--events", required=True)
        p.add_argument("--properties", required=True)
        p.add_argument("--json", action="store_true")
        p.add_argument("--ga4-param-limit", type=int, default=25,
                       help="parameters per GA4 event: 25 for standard properties, 100 for Analytics 360")
        p.add_argument("--vendor-events", default=os.path.join(ASSETS, "vendor-events.txt"),
                       help="vendor events list; its @ga4-reserved section holds GA4's reserved event names")
        p.add_argument("--vendor-params", default=os.path.join(ASSETS, "vendor-params.txt"),
                       help="vendor parameters list; its @ga4-reserved section holds GA4's reserved parameter names")
        if name == "drift":
            p.add_argument("--observed", action="append", required=True)
            p.add_argument("--reference")
            p.add_argument("--ga4-definitions", help="CSV of GA4 custom definitions: parameter_name, scope, kind")
            p.add_argument("--tool")
            p.add_argument("--window-start")
            p.add_argument("--window-end")
            p.add_argument("--as-of", help="audit date; default: the earlier of today and 4 days after --window-end")
            p.add_argument("--mismatch-share", type=float, default=0.01)
            p.add_argument("--required-fail", type=float, default=0.95)
            p.add_argument("--min-sample", type=int, default=100)
            p.add_argument("--global-share", type=float, default=0.8)
            p.add_argument("--dynamic-min", type=int, default=10)
            p.add_argument("--optional-min-rows", type=int, default=1000)
            p.add_argument("--out")
    args = parser.parse_args()
    if args.command == "quality":
        return cmd_quality(args)
    if args.command == "drift":
        return cmd_drift(args)
    parser.print_help()
    return 2


if __name__ == "__main__":
    sys.exit(main())
