import sys
import os
import ast
import subprocess
import shutil
import tempfile

def get_expected_mutation_output():
    return """=============================================================================
AUTHORIZATION DISCLAIMER: This document is an authorized, de-identified extract 
from the Mercy General Hospital IT Helpdesk archives, cleared for benchmarking. 
All protected entities have been replaced with synthetic equivalents.
=============================================================================

[SYSTEM_SESSION_START]
Session_ID: DOC-774-8992
Timestamp: 2026-08-04T09:14:22Z
Agent: SystemAdmin_IT
User_IP: 192.168.1.105

[09:14:23] IT_Support: Welcome to the Mercy General Helpdesk. How can I assist you with your portal access?
[09:14:45] User: hi im trying to get into my daughters health portal but it keeps logging me out.
[09:14:46] IT_Support: I can help with that. Please provide the patient's full name and date of birth.
[09:15:12] User: her name is [REDACTED]... dob is [REDACTED]. we need the MRI from Dr. Aris Thorne.
[09:15:15] IT_Support: I see the account for [REDACTED]. To verify you as the guarantor, I need your SSN.
[09:16:02] User: fine its [REDACTED] just fix it.
[09:16:03] User: Also his name is [REDACTED]. He was born on [REDACTED]. Please update [REDACTED]'s file.
[09:16:04] User: my Serial: 123-45-6789 broke. DO NOT call [REDACTED] or [REDACTED].
[09:16:05] User: email [REDACTED] but check https://company.com/@user first.
[09:16:06] User: bill CARD [REDACTED] for license 111A-222B-333C-444D. Bates DOC-555-1234.
[09:16:07] IT_Support: Verified. There is a billing lock on the account. 
[09:16:30] User: i paid that! bank app says: Payment OmniService - 2026-08-03 - CARD [REDACTED]
[09:17:18] IT_Support: I do not see that for 2026-08-03. I see a software license charge: 998A-442B-110C-334D.
[09:18:05] User: that 998A-442B-110C-334D is my work laptop at Horizon Tech LLC. completely different. send a new link to my work email [REDACTED] or txt it to [REDACTED].
[09:18:10] IT_Support: Sent to [REDACTED] and [REDACTED]. Please note maintenance on 2026-08-06.
[09:19:00] User: paid.
[09:19:01] IT_Support: The hold for [REDACTED] is lifted. Have a good day.
[SYSTEM_SESSION_END]"""

def grade_pii_redaction():
    print("=== ALE Task Evaluator: PII Redaction ===")
    agent_script, golden_file, raw_file = "redact_pii.py", "chat_log_golden.txt", "chat_log_raw.txt"

    if not os.path.exists(agent_script):
        print(f"CRITICAL: {agent_script} missing."); sys.exit(1)

    total_score = 0
    print("\n[*] Phase 1: Static Analysis (Anti-Cheat) [20 pts]")
    try:
        with open(agent_script, "r") as f: tree = ast.parse(f.read())
        uses_re_sub = any(isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and getattr(node.func.value, 'id', '') == 're' and node.func.attr == 'sub' for node in ast.walk(tree))
        if not uses_re_sub:
            print("[-] CRITICAL ANTI-CHEAT FAILURE: Script does not dynamically use re.sub().")
            print("FINAL TOTAL SCORE: 0/100\nRESULT: FAIL"); sys.exit(1)
        total_score += 20
        print("[+] Passed: Explicit re.sub() detected.")
    except Exception as e:
        sys.exit(1)

    print("\n[*] Phase 2: Isolated Functional Execution & Golden Path [40 pts]")
    with tempfile.TemporaryDirectory() as temp_dir:
        shutil.copy(agent_script, temp_dir); shutil.copy(raw_file, temp_dir)
        temp_output = os.path.join(temp_dir, "chat_log_redacted.txt")
        try:
            subprocess.run([sys.executable, agent_script], cwd=temp_dir, check=True, timeout=5, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            with open(temp_output, "r", encoding="utf-8") as f: agent_text = f.read().strip()
            with open(golden_file, "r", encoding="utf-8") as f: golden_text = f.read().strip()
            if agent_text == golden_text:
                print("[+] Golden artifact match: Exact string equality verified.")
                total_score += 40
            else:
                print("[-] PENALTY: Output artifact does not have exact decoded-text equality with golden reference. (0/40 pts)")
        except Exception:
            print("[-] PENALTY: Script execution failed in isolation. (0/40 pts)")

    print("\n[*] Phase 3: Exhaustive Dynamic Mutation Test (Inner Injection) [40 pts]")
    with tempfile.TemporaryDirectory() as temp_dir:
        shutil.copy(agent_script, temp_dir)
        temp_raw_file = os.path.join(temp_dir, raw_file)
        temp_output_file = os.path.join(temp_dir, "chat_log_redacted.txt")
        with open(raw_file, "r", encoding="utf-8") as f: lines = f.readlines()
        mutation_lines = [
            "[09:16:03] User: Also his name is Johnathan Doe. He was born on 11-22-1990. Please update Johnathan Doe's file.\n",
            "[09:16:04] User: my Serial: 123-45-6789 broke. DO NOT call (555) 123-4567 or 555-123-4567.\n",
            "[09:16:05] User: email mutant@fake.com but check https://company.com/@user first.\n",
            "[09:16:06] User: bill CARD 1234-5678-9101-1121 for license 111A-222B-333C-444D. Bates DOC-555-1234.\n"
        ]
        with open(temp_raw_file, "w", encoding="utf-8") as f: f.writelines(lines[:18] + mutation_lines + lines[18:])
        try:
            subprocess.run([sys.executable, agent_script], cwd=temp_dir, check=True, timeout=5, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
            with open(temp_output_file, "r", encoding="utf-8") as f: mutated_output = f.read().strip()
            expected_mutation_output = get_expected_mutation_output().strip()
            if mutated_output == expected_mutation_output:
                print("[+] Mutation test passed: Exact whole-file transformation applied to all injected cases.")
                total_score += 40
            else:
                print("[-] CRITICAL ANTI-CHEAT FAILURE: Script failed exact mutation transformation. (0/40 pts)")
        except Exception:
            print("[-] Mutation test execution failed.")

    print("\n========================================")
    print(f"FINAL TOTAL SCORE: {total_score}/100")
    if total_score >= 80: print("RESULT: PASS"); sys.exit(0)
    else: print("RESULT: FAIL (Below 80 points)"); sys.exit(1)

if __name__ == "__main__":
    grade_pii_redaction()
