from __future__ import annotations

from typing import Any, Dict, List

from pydantic import BaseModel


class NormalizedSfError(BaseModel):
    kind: str
    message: str
    hints: List[str] = []


def _extract_error_fields(raw: Any) -> Dict[str, str]:
    if isinstance(raw, dict):
        return {
            "code": str(raw.get("errorCode") or raw.get("error") or ""),
            "message": str(raw.get("message") or raw.get("error_description") or ""),
        }
    message = str(raw)
    code = getattr(raw, "code", "") or getattr(raw, "status", "") or ""
    return {"code": str(code), "message": message}


def normalize_sf_error(raw: Any) -> NormalizedSfError:
    details = _extract_error_fields(raw)
    code = (details.get("code") or "").upper()
    message = details.get("message") or "Salesforce error"

    if "INVALID_FIELD" in code or "NO_SUCH_COLUMN" in code:
        return NormalizedSfError(
            kind="invalid_field",
            message=message,
            hints=[
                "Verify relationship names (e.g., OpportunityContactRoles.Contact.Email).",
                "Use parent lookups like Account.Name on Opportunity instead of child references.",
            ],
        )

    if "INVALID_TYPE" in code or "INVALID_RELATIONSHIP" in code:
        return NormalizedSfError(
            kind="invalid_relationship",
            message=message,
            hints=[
                "Confirm the relationship path; some joins require junction objects like OpportunityContactRole.",
            ],
        )

    if (
        "INSUFFICIENT_ACCESS" in code
        or "INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY" in code
    ):
        return NormalizedSfError(
            kind="insufficient_access",
            message=message,
            hints=[
                "You may lack permission for one or more fields. Remove sensitive fields (e.g., Contact.Email) and retry.",
            ],
        )

    if "REQUEST_LIMIT_EXCEEDED" in code or "QUERY_TIMEOUT" in code:
        return NormalizedSfError(
            kind="rate_limit",
            message=message,
            hints=[
                "Retry later, tighten filters, or schedule the report to run offline.",
            ],
        )

    if "MALFORMED_QUERY" in code:
        return NormalizedSfError(
            kind="malformed_query",
            message=message,
            hints=[
                "Check SELECT/WHERE syntax and date literals (THIS_QUARTER, LAST_N_DAYS:90).",
            ],
        )

    return NormalizedSfError(
        kind="unknown",
        message=message,
        hints=["Edit the plan or open the query in manual SOQL mode."],
    )
