"""Shared SOQL policy helpers for query-builder and execution paths."""

from __future__ import annotations

from typing import Dict, List, Optional, Set

# Allowlist for safe SOQL queries executed via /api/v2/salesforce/query.
# This keeps the generic query endpoint usable for client features (e.g., dedupe)
# while ensuring only a vetted set of objects/fields can be requested.
SAFE_SOQL_ALLOWLIST: Dict[str, List[str]] = {
    "Lead": [
        "Id",
        "Name",
        "FirstName",
        "LastName",
        "Company",
        "Email",
        "Phone",
        "MobilePhone",
        "Title",
        "City",
        "State",
        "PostalCode",
        "Country",
        "Industry",
        "LeadSource",
        "Website",
        "Status",
        "OwnerId",
        "CreatedDate",
        "LastModifiedDate",
    ],
    "Contact": [
        "Id",
        "Name",
        "FirstName",
        "LastName",
        "Email",
        "Phone",
        "MobilePhone",
        "Title",
        "Department",
        "AccountId",
        "MailingCity",
        "MailingState",
        "MailingCountry",
        "OwnerId",
        "CreatedDate",
        "LastModifiedDate",
    ],
    "Account": [
        "Id",
        "Name",
        "Website",
        "Phone",
        "BillingStreet",
        "BillingCity",
        "BillingState",
        "BillingPostalCode",
        "BillingCountry",
        "Industry",
        "Type",
        "ParentId",
        "OwnerId",
        "CreatedDate",
        "LastModifiedDate",
    ],
    # Related objects referenced via lookups (Owner.Name, etc.)
    "User": [
        "Id",
        "Name",
    ],
}

SAFE_RELATIONSHIP_ALIAS_OBJECTS: Dict[str, str] = {
    "owner": "User",
    "createdby": "User",
    "lastmodifiedby": "User",
    "account": "Account",
    "parent": "Account",
    "contact": "Contact",
}

_SAFE_OBJECT_NAME_MAP = {
    str(object_name or "").strip().lower(): object_name
    for object_name in SAFE_SOQL_ALLOWLIST.keys()
}


def canonical_safe_object_name(object_name: Optional[str]) -> Optional[str]:
    """Return canonical object API name if object is allowlisted, else None."""
    key = str(object_name or "").strip().lower()
    if not key:
        return None
    return _SAFE_OBJECT_NAME_MAP.get(key)


def safe_field_names_for_object(object_name: Optional[str]) -> Optional[Set[str]]:
    """Return lower-cased allowlisted field names for object, else None."""
    canonical_object = canonical_safe_object_name(object_name)
    if not canonical_object:
        return None
    return {
        str(field_name or "").strip().lower()
        for field_name in SAFE_SOQL_ALLOWLIST.get(canonical_object, [])
        if str(field_name or "").strip()
    }


def build_safe_plan_allowlist() -> Dict[str, List[str]]:
    """Return a defensive copy of the static SOQL allowlist."""
    return {obj: fields[:] for obj, fields in SAFE_SOQL_ALLOWLIST.items()}


def safe_relationship_object_for_alias(alias: Optional[str]) -> Optional[str]:
    """Return canonical related object for a relationship alias if known."""
    key = str(alias or "").strip().lower()
    if not key:
        return None
    return SAFE_RELATIONSHIP_ALIAS_OBJECTS.get(key)
