#!/usr/bin/env python3
"""Detect duplicate top-level variable definitions in Pine Script files.

Exits 1 and prints offending names+lines if duplicates are found.
Usage: python3 tools/check_pine_duplicates.py [file ...]
  Defaults to strategies/*.pine if no args given.
"""

import re
import sys
from glob import glob
from pathlib import Path

SKIP_KEYWORDS = {
    "if", "for", "while", "switch", "var", "varip", "true", "false", "na",
    "_", "import", "export", "method", "type",
}

# Matches: optional type keyword, then identifier, then = (not ==)
ASSIGN_RE = re.compile(
    r"^\s*(?:float|int|bool|string|color|label|line|array|matrix|map|box|table)?"
    r"\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*=[^=]"
)

# Lines that start a block (not assignments despite having =)
BLOCK_START_RE = re.compile(r"^\s*(?:if|for|while|switch)\b")


def check_file(path: str) -> list[tuple[str, int, int]]:
    """Return list of (varname, first_line, dup_line) for each duplicate."""
    duplicates = []
    seen: dict[str, int] = {}
    paren_depth = 0
    with open(path, encoding="utf-8") as fh:
        for lineno, raw in enumerate(fh, 1):
            line = raw.rstrip()
            # Track parenthesis depth so we skip named-parameter assignments
            # (e.g. tooltip="...", title="..." inside input.float() continuations).
            # Check depth at start of line so valid assignments that open parens
            # (e.g. `x = f(...)`) are still captured.
            depth_at_start = paren_depth
            paren_depth += line.count("(") - line.count(")")
            paren_depth = max(0, paren_depth)
            if depth_at_start > 0:
                continue
            if BLOCK_START_RE.match(line):
                continue
            m = ASSIGN_RE.match(line)
            if not m:
                continue
            name = m.group(1)
            if name in SKIP_KEYWORDS:
                continue
            if name in seen:
                duplicates.append((name, seen[name], lineno))
            else:
                seen[name] = lineno
    return duplicates


def main() -> int:
    targets = sys.argv[1:] or sorted(glob("strategies/*.pine"))
    if not targets:
        print("No Pine files found.", file=sys.stderr)
        return 0

    total_dupes = 0
    for path in targets:
        if not Path(path).is_file():
            continue
        dupes = check_file(path)
        if dupes:
            print(f"❌  {path}")
            for name, first, dup in dupes:
                print(f"    '{name}' first at line {first}, redefined at line {dup}")
            total_dupes += len(dupes)

    if total_dupes:
        print(f"\nFix: remove or rename the later definition(s) listed above.")
        return 1

    print("✅  No duplicate variable definitions found in Pine files.")
    return 0


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