"""Safety policy enforcement for Salesforce CLI commands.

This module is the single enforcement point for the read-only safety policy.
Every sf CLI command MUST pass through validate_sf_command() before execution.
If a command is not on the whitelist, it is blocked -- no exceptions.
"""

import re

ALLOWED_SF_SUBCOMMANDS: set[str] = {
    "org login web",
    "org list",
    "org display",
    "project generate",
    "project retrieve start",
    "package installed list",
    "sobject list",
    "sobject describe",
    "data query",
}

BLOCKED_KEYWORDS: set[str] = {
    "deploy",
    "push",
    "delete",
    "insert",
    "update",
    "upsert",
    "undelete",
    "destroy",
    "execute",
    "apex run",
}


class SafetyViolationError(Exception):
    """Raised when a command violates the read-only safety policy."""


def validate_sf_command(command: str) -> None:
    """Validate that an sf CLI command is on the whitelist.

    Raises SafetyViolationError if the command is not permitted.
    """
    normalized = " ".join(command.strip().split())

    for blocked in BLOCKED_KEYWORDS:
        if blocked in normalized.lower():
            raise SafetyViolationError(
                f"BLOCKED: Command contains '{blocked}' which is prohibited. "
                f"This MCP server is strictly read-only against customer orgs. "
                f"Command: {command}"
            )

    is_allowed = False
    for allowed in ALLOWED_SF_SUBCOMMANDS:
        if allowed in normalized:
            is_allowed = True
            break

    if not is_allowed:
        raise SafetyViolationError(
            f"BLOCKED: Command not on the whitelist of permitted sf commands. "
            f"Allowed: {sorted(ALLOWED_SF_SUBCOMMANDS)}. "
            f"Command: {command}"
        )


def validate_soql_query(query: str) -> None:
    """Validate that a SOQL query is read-only and safe.

    Blocks queries against business data objects. Only CS-namespaced
    custom settings and metadata objects are permitted.
    """
    normalized = query.strip().upper()

    if not normalized.startswith("SELECT"):
        raise SafetyViolationError(
            f"BLOCKED: Only SELECT queries are permitted. Query: {query}"
        )

    dml_patterns = ["INSERT", "UPDATE", "DELETE", "UPSERT", "MERGE"]
    for pattern in dml_patterns:
        if re.search(rf"\b{pattern}\b", normalized):
            raise SafetyViolationError(
                f"BLOCKED: DML keyword '{pattern}' found in query. "
                f"Only read-only SELECT queries are permitted. Query: {query}"
            )

    business_objects = [
        "ACCOUNT", "CONTACT", "LEAD", "OPPORTUNITY", "CASE",
        "CONTRACT", "TASK", "EVENT", "CAMPAIGN",
    ]
    for obj in business_objects:
        if re.search(rf"\bFROM\s+{obj}\b", normalized):
            raise SafetyViolationError(
                f"BLOCKED: Querying business object '{obj}' is not permitted. "
                f"Only CloudSense configuration objects are allowed. Query: {query}"
            )
