"""Execute deterministic PromQL tests with an installed official promtool.
No Prometheus server, production data, remote API, or timing benchmark.
Usage: python3 experiment.py --promtool /path/to/promtool
"""
import argparse,json,subprocess
from pathlib import Path

CASES = [
    ('no_reset',100,110,50,60,20,20),
    ('visible_drop',100,110,50,5,15,115),
    ('hidden_drop',100,200,50,5,105,55),
    ('flat_sum',100,145,50,5,50,0),
    ('both_reset',100,2,50,3,5.000000000000001,5),
]
GOOD = '60 * sum by (scenario) (rate(requests_total[2m]))'
BAD = '60 * rate(service:requests:raw_sum[2m])'
RULE = '''groups:
  - name: raw-counter-sum-for-negative-control
    interval: 1m
    rules:
      - record: service:requests:raw_sum
        expr: sum by (scenario) (requests_total)
'''

def fixture():
    lines=['rule_files:','  - counter.rules.yml','evaluation_interval: 1m','tests:',
           '  - interval: 1m','    input_series:']
    for name,a0,a1,b0,b1,good,bad in CASES:
        for instance,x,y in [('a',a0,a1),('b',b0,b1)]:
            lines += [f'      - series: \'requests_total{{scenario="{name}",instance="{instance}"}}\'',
                      f"        values: '{x} {x} {y}'"]
    lines += ['    promql_expr_test:']
    for expression,index in [(GOOD,5),(BAD,6)]:
        lines += [f"      - expr: '{expression}'",'        eval_time: 2m','        exp_samples:']
        for case in CASES:
            lines += [f'          - labels: \'{{scenario="{case[0]}"}}\'',f'            value: {case[index]}']
    # A single usable sample does not become a zero rate.
    lines += ['  - interval: 1m','    input_series:',
              '      - series: \'requests_total{scenario="one_sample",instance="a"}\'',
              "        values: '_ _ 10'",'    promql_expr_test:',
              "      - expr: 'rate(requests_total[2m])'",'        eval_time: 2m','        exp_samples: []']
    return '\n'.join(lines)+'\n'

def main():
    parser=argparse.ArgumentParser();parser.add_argument('--promtool',default='promtool');args=parser.parse_args()
    binary=str(Path(args.promtool).resolve()) if '/' in args.promtool else args.promtool
    version=subprocess.run([binary,'--version'],capture_output=True,text=True,check=True)
    Path('counter.rules.yml').write_text(RULE);Path('counter.test.yml').write_text(fixture())
    checked=subprocess.run([binary,'check','rules','counter.rules.yml'],capture_output=True,text=True,check=True)
    tested=subprocess.run([binary,'test','rules','counter.test.yml'],capture_output=True,text=True)
    Path('promtool-output.txt').write_text(version.stdout+version.stderr+checked.stdout+checked.stderr+tested.stdout+tested.stderr)
    if tested.returncode:
        print(tested.stdout+tested.stderr);raise SystemExit(tested.returncode)
    assert 'SUCCESS' in tested.stdout
    rows=[dict(scenario=n,a=[a0,a0,a1],b=[b0,b0,b1],rate_then_sum_per_minute=g,
               sum_then_rate_per_minute=d,difference=d-g)for n,a0,a1,b0,b1,g,d in CASES]
    result=dict(scope='Synthetic PromQL unit tests; expected vectors verified by real promtool',
                promtool_version=(version.stdout+version.stderr).splitlines()[0],
                sample_times_seconds=[0,60,120],eval_time_seconds=120,range_seconds=120,
                rule_interval_seconds=60,queries=dict(rate_then_sum=GOOD,sum_then_rate=BAD),
                verified_vector_values=10,empty_vector_assertions=1,cases=rows,
                note='Values below are explicit expectations confirmed by passing engine tests, not scraped production observations.',
                process=dict(check_rules_exit=checked.returncode,test_rules_exit=tested.returncode),
                exclusions=['No live scraping','No production traffic','No recording-rule scheduling lag',
                            'No native histogram, HA deduplication or out-of-order sample test'])
    Path('results.json').write_text(json.dumps(result,indent=2)+'\n')
    print(json.dumps([(r['scenario'],r['rate_then_sum_per_minute'],r['sum_then_rate_per_minute'])for r in rows]))

if __name__=='__main__':main()
