"""Safety policy enforcement for Salesforce CLI commands.

Every sf CLI command MUST pass through validate_sf_command() before execution.
If a command is not on the whitelist, it is blocked.
"""

import re


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

LMA_ALLOWED_OBJECTS: set[str] = {
    "ACCOUNT",
    "SFLMA__LICENSE__C",
    "SFLMA__PACKAGE__C",
    "SFLMA__PACKAGE_VERSION__C",
    "SUBSCRIBERPACKAGE",
}

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."""
    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"Command: {command}"
            )

    if not any(allowed in normalized for allowed in ALLOWED_SF_SUBCOMMANDS):
        raise SafetyViolationError(
            f"BLOCKED: Command not on the whitelist. "
            f"Allowed: {sorted(ALLOWED_SF_SUBCOMMANDS)}. "
            f"Command: {command}"
        )


def validate_soql_query(
    query: str,
    *,
    target_org: str | None = None,
    lma_org: str | None = None,
) -> None:
    """Validate that a SOQL query is read-only and safe."""
    normalized = query.strip().upper()

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

    for keyword in ("INSERT", "UPDATE", "DELETE", "UPSERT", "MERGE"):
        if re.search(rf"\b{keyword}\b", normalized):
            raise SafetyViolationError(
                f"BLOCKED: DML keyword '{keyword}' found. Query: {query}"
            )

    is_lma_context = (
        target_org is not None
        and lma_org is not None
        and target_org == lma_org
    )

    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):
            if is_lma_context and obj in LMA_ALLOWED_OBJECTS:
                continue
            raise SafetyViolationError(
                f"BLOCKED: Querying business object '{obj}' is not permitted. "
                f"Query: {query}"
            )
