#!/usr/bin/env python3
"""Re-run the qr-code-photo-sharing evidence check.

Fetches every URL named in dataset.json and reports, per option and property,
whether the quote backing it still appears on the page (or, for an 'absent'
entry, still does not). Rows citing Viallo source code are read from the
repository this folder sits in, and skipped when the script runs outside it.

Usage: python3 check.py [--recheck] [path/to/dataset.json]
Every step is a page fetch or a file read, so --recheck runs the same check.
Exits 0 when every quote still holds, 1 otherwise.
"""
import html
import json
import re
import subprocess
import sys
from pathlib import Path

# support.google.com serves a different help variant per client: the Safari UA gets the
# "Computer" page, the bare UA the "Android phone & tablet" one. Quotes are checked against
# the first, then against the second before a cell is reported missing.
UA = ('Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/605.1.15 '
      '(KHTML, like Gecko) Version/17.0 Safari/605.1.15')
UA_ALT = 'Mozilla/5.0'
# apps/web/public/blog/<slug>/check.py -> repository root
REPO = Path(__file__).resolve().parents[5]


def fetch(url, ua=UA):
    proc = subprocess.run(
        ['curl', '-sL', '--compressed', '-m', '40', '-A', ua,
         '-H', 'Accept-Language: en-US,en', '-w', '\n%{http_code}', url],
        capture_output=True,
    )
    body, _, code = proc.stdout.decode('utf-8', 'ignore').rpartition('\n')
    return code.strip(), body


def norm(s):
    s = html.unescape(s)
    for a, b in (('\u2019', "'"), ('\u2018', "'"), ('\u201c', '"'), ('\u201d', '"'),
                 ('\u2013', '-'), ('\u2014', '-'), ('\u00a0', ' ')):
        s = s.replace(a, b)
    return re.sub(r'\s+', ' ', s).strip().lower()


def to_text(page):
    page = re.sub(r'(?is)<(script|style)[^>]*>.*?</\1>', ' ', page)
    page = re.sub(r'<[^>]+>', ' ', page)
    return norm(page)


def main():
    args = [a for a in sys.argv[1:] if a != '--recheck']
    path = Path(args[0]) if args else Path(__file__).with_name('dataset.json')
    data = json.loads(path.read_text())
    print(f"method {data['method']}, checkedAt {data['checkedAt']}\n")

    pages, pages_alt, json_pages, files = {}, {}, {}, {}
    for url in data['inputs']:
        if url.startswith('file '):
            continue
        code, body = fetch(url)
        pages[url] = (code, to_text(body), norm(body))
        print(f'HTTP {code}  {url}')
    print()

    def alt(url):
        if url not in pages_alt:
            code, body = fetch(url, UA_ALT)
            pages_alt[url] = (code, to_text(body), norm(body))
        return pages_alt[url]

    def source(rel):
        if rel not in files:
            p = REPO / rel
            files[rel] = norm(p.read_text(errors='ignore')) if p.is_file() else None
        return files[rel]

    counts = {'found': 0, 'missing': 0, 'skipped': 0}

    def report(kind, label, detail):
        counts[kind] += 1
        tag = {'found': 'FOUND   ', 'missing': 'MISSING ', 'skipped': 'SKIP    '}[kind]
        print(f'{tag} {label} ({detail})')

    def check_one(label, q):
        if 'file' in q:
            text = source(q['file'])
            if text is None:
                report('skipped', label, f"{q['file']} not in this checkout")
            elif 'absent' in q:
                ok = norm(q['absent']) not in text
                report('found' if ok else 'missing', label,
                       f"{q['file']}: {q['absent']!r} {'absent' if ok else 'now present'}")
            else:
                ok = norm(q['quote']) in text
                report('found' if ok else 'missing', label,
                       q['file'] if ok else f"{q['file']}: {q['quote']!r}")
            return
        url = q['url']
        if 'json' in q:
            spec = q['json']
            if url not in json_pages:
                try:
                    json_pages[url] = json.loads(fetch(url)[1])
                except ValueError:
                    json_pages[url] = {'prices': {}}
            cell = json_pages[url].get('prices', {}).get(spec['id'], '')
            cell = html.unescape(re.sub(r'<[^>]+>', '', cell))
            ok = spec['contains'] in cell
            report('found' if ok else 'missing', label,
                   f"json {spec['id']} -> {cell!r}" + ('' if ok else f' at {url}'))
            return
        code, text, raw = pages[url]
        if 'absent' in q:
            needle = norm(q['absent'])
            ok = not re.search(r'\b' + re.escape(needle) + r'\b', text)
            report('found' if ok else 'missing', label,
                   f"HTTP {code}, {q['absent']!r} {'absent' if ok else 'now on the page'} at {url}")
            return
        nq = norm(q['quote'])
        if nq in text or nq in raw:
            report('found', label, f'HTTP {code}')
            return
        code, text, raw = alt(url)
        if nq in text or nq in raw:
            report('found', label, f'HTTP {code}, alternate client variant')
        else:
            report('missing', label, f"HTTP {code}: {q['quote']!r} at {url}")

    for row in data['results']:
        for prop in data['properties']:
            cell = row[prop]
            label = f"{row['option']} / {prop}"
            if not cell['quotes']:
                report('skipped', label, cell['value'])
            for q in cell['quotes']:
                check_one(label, q)

    for fact in data.get('supporting', []):
        for q in fact['quotes']:
            entry = {'quote': q, 'file': fact['file']} if 'file' in fact else {'quote': q, 'url': fact['url']}
            check_one(f"supporting / {fact['claim']}", entry)

    print(f"\n{counts['found']} found, {counts['missing']} missing, "
          f"{counts['skipped']} skipped (not checked, or source file outside this checkout)")
    return 1 if counts['missing'] else 0


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