from typing import Optional

from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict

CASTOR_ENV_PREFIX = "CASTOR_SALESFORCE_"


class SalesforceCredentials(BaseSettings):
    """
    Class to handle Salesforce rest API permissions
    """

    model_config = SettingsConfigDict(
        env_prefix=CASTOR_ENV_PREFIX,
        extra="ignore",
        populate_by_name=True,
    )

    base_url: str
    client_id: str
    client_secret: str = Field(repr=False)
    password: Optional[str] = Field(repr=False, default=None)
    security_token: Optional[str] = Field(repr=False, default=None)
    username: Optional[str] = None

    @property
    def password_token(self) -> str:
        """Generates the password for authentication"""
        assert self.password  # for mypy
        assert self.security_token  # for mypy
        return self.password + self.security_token

    def token_request_payload(self) -> dict[str, str]:
        """
        Params to post to the API in order to retrieve the authentication token
        """
        if all(
            v is None
            for v in (self.username, self.password, self.security_token)
        ):
            return {
                "grant_type": "client_credentials",
                "client_id": self.client_id,
                "client_secret": self.client_secret,
            }

        for key in ("username", "password", "security_token"):
            if getattr(self, key) is None:
                raise ValueError(
                    "'{}' was not provided. It is required for Basic Authentication. If you intend to use Credential Client Flow, make sure not to provide any of: \
                    username, password, security_token".format(key)
                )
        assert self.username  # for mypy
        assert self.password  # for mypy
        assert self.security_token  # for mypy
        return {
            "grant_type": "password",
            "client_id": self.client_id,
            "client_secret": self.client_secret,
            "username": self.username,
            "password": self.password_token,
        }
