#!/usr/bin/env python3
"""
Parse cards.js correctly — handles // comments interspersed with card objects.

Bugs fixed vs. previous version:
  1. Key-parsing while-loop had operator precedence error:
     `while j < n and s[j].isidentifier() or s[j] in '_$':`
     → crashes with IndexError when j >= n.
     Fixed: `while j < n and (s[j].isidentifier() or s[j] in '_$'):`

  2. Line-by-line comment stripping left empty lines that confused the
     bracket counter. Replaced with a character-level comment stripper
     that handles both // and /* */ comments correctly inside/outside strings.
"""

import sys
from pathlib import Path


def strip_js_comments(source: str) -> str:
    """Remove // and /* */ comments, preserving string contents."""
    out = []
    i = 0
    n = len(source)
    in_line = False
    in_block = False
    in_str = False
    str_char = None
    escaped = False

    while i < n:
        c = source[i]

        if escaped:
            out.append(c)
            escaped = False
            i += 1
            continue

        if in_str:
            if c == '\\':
                escaped = True
                out.append(c)
            elif c == str_char:
                in_str = False
                out.append(c)
            else:
                out.append(c)
            i += 1
            continue

        if in_line:
            if c == '\n':
                in_line = False
                out.append(c)
            i += 1
            continue

        if in_block:
            if c == '*' and i + 1 < n and source[i + 1] == '/':
                in_block = False
                i += 2
                continue
            i += 1
            continue

        # Not in any comment or string
        if c == '/' and i + 1 < n:
            nxt = source[i + 1]
            if nxt == '/':
                in_line = True
                i += 2
                continue
            if nxt == '*':
                in_block = True
                i += 2
                continue

        if c in ('"', "'"):
            in_str = True
            str_char = c
            out.append(c)
            i += 1
            continue

        out.append(c)
        i += 1

    return ''.join(out)


def parse_js_string(s: str, i: int):
    """Parse a double-quoted JS string. Returns (str, new_i)."""
    assert s[i] == '"'
    result = []
    i += 1
    n = len(s)
    while i < n:
        c = s[i]
        if c == '\\':
            i += 1
            if i < n:
                table = {'"': '"', '\\': '\\', 'n': '\n', 't': '\t',
                         'b': '\b', 'f': '\f', '/': '/'}
                result.append(table.get(s[i], '\\' + s[i]))
                i += 1
        elif c == '"':
            i += 1
            return ''.join(result), i
        else:
            result.append(c)
            i += 1
    raise ValueError(f"Unterminated string at pos {i - 1}")


def parse_js_value(s: str, i: int):
    """Parse any JS value. Returns (value, new_i)."""
    n = len(s)
    while i < n and s[i] in ' \t\n\r':
        i += 1
    if i >= n:
        return None, i

    c = s[i]
    if c == '"':
        return parse_js_string(s, i)
    if c == '{':
        return parse_js_object(s, i)
    if c == '[':
        return parse_js_array(s, i)
    if s[i:i + 4] == 'true':
        return True, i + 4
    if s[i:i + 5] == 'false':
        return False, i + 5
    if s[i:i + 4] == 'null':
        return None, i + 4

    j = i
    while j < n and (s[j].isidentifier() or s[j] in '_$'):
        j += 1
    if j == i:  # number
        while j < n and s[j] not in ',]}; \t\n\r':
            j += 1
    return s[i:j], j


def parse_js_object(s: str, i: int):
    """Parse a JS object { ... }. Returns (dict, new_i)."""
    assert s[i] == '{'
    result = {}
    i += 1
    n = len(s)
    while i < n:
        while i < n and s[i] in ' \t\n\r,':
            i += 1
        if i >= n:
            break
        if s[i] == '}':
            i += 1
            return result, i
        # key: string or identifier
        if s[i] == '"':
            key, i = parse_js_string(s, i)
        else:
            j = i
            while j < n and (s[j].isidentifier() or s[j] in '_$'):
                j += 1
            key = s[i:j]
            i = j
        while i < n and s[i] in ' \t\n\r':
            i += 1
        if i < n and s[i] == ':':
            i += 1
        val, i = parse_js_value(s, i)
        result[key] = val
    raise ValueError(f"Unterminated object at pos {i}")


def parse_js_array(s: str, i: int):
    """Parse a JS array [ ... ]. Returns (list, new_i)."""
    assert s[i] == '['
    result = []
    i += 1
    n = len(s)
    while i < n:
        while i < n and s[i] in ' \t\n\r,':
            i += 1
        if i >= n:
            break
        if s[i] == ']':
            i += 1
            return result, i
        val, i = parse_js_value(s, i)
        result.append(val)
    raise ValueError(f"Unterminated array at pos {i}")


# ── Main ────────────────────────────────────────────────────────────────

def main():
    path = "/Users/brians/Documents/AveryArt/Gallery Drill/cards.js"
    source = Path(path).read_text(encoding='utf-8')
    clean = strip_js_comments(source)

    start = clean.find('window.CARDS = ')
    if start < 0:
        print("ERROR: Cannot find window.CARDS")
        sys.exit(1)
    arr_start = clean.find('[', start)
    cards, _ = parse_js_array(clean, arr_start)

    print(f"Total cards: {len(cards)}")
    cats = {}
    for c in cards:
        d = c.get('d', '???')
        cats[d] = cats.get(d, 0) + 1
    for cat, n in sorted(cats.items()):
        print(f"  {cat:<20} {n} cards")
    print()

    seen = set()
    for c in cards:
        d = c.get('d', '')
        if d not in seen:
            seen.add(d)
            print(f"  [{d}] Q: {c.get('q', '')[:80]}")

    print()
    for c in cards:
        q = c.get('q', '')
        if 'Banksy' in q and 'buyer' in q.lower():
            print("Sample — Banksy what is the buyer:")
            print(f"  Q: {q}")
            print(f"  A: {c.get('a', '')[:200]}")
            break

    # Write deck data for COACH
    out = Path("/Users/brians/Documents/AveryArt/deck_data.json")
    import json
    with out.open("w", encoding="utf-8") as f:
        json.dump(cards, f, ensure_ascii=False, indent=2)
    print(f"\nWrote {out} — {len(cards)} cards for COACH")


if __name__ == '__main__':
    main()
