"""SHA-256 hashing utilities for the Garanti BBVA Switch API.

The Switch API uses SHA-256 (unlike the VPServlet API which uses SHA-1).
All Switch API requests require a ``hashedData`` field in the header,
computed by concatenating specific fields and hashing with SHA-256.

Request hash formula::

    UPPERCASE(SHA256(requestId + swtId + userId + timestamp + swtPassword))

Response hash verification formula::

    UPPERCASE(SHA256(requestId + swtId + returnCode + reasonCode + message + timestamp + swtPassword))

Reference:
    https://dev.garantibbva.com.tr/kart-saklama-api-istegi-ile-token-alma
"""

import hashlib


def sha256(data: str) -> str:
    """Compute the SHA-256 hex digest of a UTF-8 encoded string.

    Args:
        data: The input string to hash.

    Returns:
        Lowercase hexadecimal SHA-256 digest string.

    Example::

        >>> from garantipay.switch_hash import sha256
        >>> sha256("hello")
        '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
    """
    hasher = hashlib.sha256()
    hasher.update(data.encode("utf-8"))
    return hasher.hexdigest()


def compute_switch_request_hash(
    request_id: str,
    swt_id: str,
    user_id: str,
    timestamp: str,
    swt_password: str,
) -> str:
    """Compute the ``hashedData`` field for a Switch API request header.

    Formula::

        UPPERCASE(SHA256(requestId + swtId + userId + timestamp + swtPassword))

    Args:
        request_id: Unique request identifier (max 36 characters).
        swt_id: Switch ID assigned to your merchant account.
        user_id: User ID for the request.
        timestamp: Timestamp string for the request.
        swt_password: Your Switch password.

    Returns:
        Uppercase hexadecimal SHA-256 hash string.

    Example::

        >>> from garantipay.switch_hash import compute_switch_request_hash
        >>> compute_switch_request_hash(
        ...     request_id="unique_request_id",
        ...     swt_id="CC82C381E078482AB328943FCCB7100C",
        ...     user_id="your_user_id",
        ...     timestamp="15032021151020",
        ...     swt_password="123asdASD@",
        ... )
        '1188B66CDFDDBAAD848CDFCC0749E1B41BC0AD8BD7F9D6004E45517400095933'
    """
    concatenated = f"{request_id}{swt_id}{user_id}{timestamp}{swt_password}"
    return sha256(concatenated).upper()


def verify_switch_response_hash(
    request_id: str,
    swt_id: str,
    return_code: str,
    reason_code: str,
    message: str,
    timestamp: str,
    swt_password: str,
    expected_hash: str,
) -> bool:
    """Verify the ``hashedData`` field from a Switch API response.

    The response timestamp is a Unix timestamp (integer) that must be
    converted to a string for hash computation.

    Formula::

        UPPERCASE(SHA256(requestId + swtId + returnCode + reasonCode + message + timestamp + swtPassword))

    Args:
        request_id: The ``requestId`` from the response header.
        swt_id: The ``swtId`` from the response header.
        return_code: The ``returnCode`` from the response header.
        reason_code: The ``reasonCode`` from the response header.
        message: The ``message`` from the response header.
        timestamp: The ``timestamp`` from the response header, as a string.
            The API returns this as a Unix timestamp integer; convert it
            to string before passing.
        swt_password: Your Switch password.
        expected_hash: The ``hashedData`` value from the response header
            to verify against.

    Returns:
        ``True`` if the computed hash matches the expected hash,
        ``False`` otherwise.

    Example::

        >>> from garantipay.switch_hash import verify_switch_response_hash
        >>> verify_switch_response_hash(
        ...     request_id="ba0e96080c7b4216847ef71197d4ad06",
        ...     swt_id="CC82C381E078482AB328943FCCB7100C",
        ...     return_code="00",
        ...     reason_code="00",
        ...     message="Basarili",
        ...     timestamp="1615734734018",
        ...     swt_password="123asdASD@",
        ...     expected_hash="937D994CF3CB41912FE...",
        ... )  # doctest: +SKIP
        True
    """
    concatenated = (
        f"{request_id}{swt_id}{return_code}{reason_code}"
        f"{message}{timestamp}{swt_password}"
    )
    computed = sha256(concatenated).upper()
    return computed == expected_hash
