"""
Tenant filter enforcement check.

Scans endpoint and service files for SQLAlchemy select() calls on known
tenant tables and warns when account_id or tenant_filter is not present
in the surrounding 15 lines (the typical extent of a single query).

Usage:
    python scripts/check_tenant_filters.py          # warn mode (exits 0)
    python scripts/check_tenant_filters.py --fail   # block mode (exits 1 on findings)
"""
import re
import sys
from pathlib import Path

# Tables that must always be filtered by account_id or tenant_filter.
# Extend this list as new tenant tables are added.
TENANT_MODELS = [
    "Tree", "AISession", "Session", "StepLibrary", "FlowProposal",
    "CopilotConversation", "AssistantChat", "FileUpload", "KBImport",
    "PsaConnection", "PsaPostLog", "PsaMemberMapping", "AIChatSession",
    "AIConversation", "AIUsage", "Subscription", "AccountInvite",
    "Notification", "NotificationConfig", "SessionShare", "UserFolder",
    "UserPinnedTree", "SessionBranch", "SessionHandoff",
    "SessionResolutionOutput", "ForkPoint", "AISessionStep",
    "AISuggestion", "StepCategory", "TreeCategory", "TreeTag",
    "Attachment", "SessionSupportingData", "MaintenanceSchedule",
    "AuditLog", "ScriptBuilderSession", "ScriptTemplate",
    "StepRating", "StepUsageLog", "TargetList",
]

# Directories to scan
SCAN_DIRS = [
    Path("app/api/endpoints"),
    Path("app/services"),
]

# Patterns that indicate the query is correctly scoped.
# NOTE: user_id scoping is accepted for user-owned resources (sessions, folders, notifications).
# For account-shared resources (trees, steps, etc.) use tenant_filter or account_id.
SAFE_PATTERNS = [
    r"tenant_filter",
    r"account_id",
    r"user_id",               # User-scoped resources (sessions, folders, notifications, etc.)
    r"is_super_admin",        # Super admin queries intentionally bypass tenant filter
    r"# cross-tenant: approved",  # Explicit approval comment
]

SKIP_FILES = {
    "admin.py",           # Super admin endpoints intentionally bypass tenant filter
    "admin_gallery.py",   # Gallery management — super admin only, no tenant scoping needed
    "public_templates.py",# Public template browser — intentionally cross-tenant
    "auth.py",            # Auth/registration — no account context during login/register
    "ratings.py",         # Session ratings — user-scoped via session lookup chain
}

findings = []

for scan_dir in SCAN_DIRS:
    if not scan_dir.exists():
        continue
    for path in sorted(scan_dir.glob("*.py")):
        if path.name in SKIP_FILES:
            continue
        lines = path.read_text().splitlines()
        for i, line in enumerate(lines):
            for model in TENANT_MODELS:
                if re.search(rf"\bselect\s*\(\s*{model}\b", line):
                    # Check surrounding 15 lines for a safe pattern
                    start = max(0, i - 2)
                    end = min(len(lines), i + 15)
                    context = "\n".join(lines[start:end])
                    if not any(re.search(p, context) for p in SAFE_PATTERNS):
                        findings.append(
                            f"{path}:{i + 1}: select({model}) — no tenant_filter or account_id found in context"
                        )

if findings:
    print(f"\n⚠  Tenant filter check — {len(findings)} warning(s):\n")
    for f in findings:
        print(f"  {f}")
    print()
    if "--fail" in sys.argv:
        print("Run with --fail: exiting 1")
        sys.exit(1)
    else:
        print("Run in warn mode — not blocking. Pass --fail to block.")
        sys.exit(0)
else:
    print("✓ Tenant filter check passed — no unscoped tenant table queries found.")
    sys.exit(0)
