"""NMEA 0183 checksum validation."""


def calculate_checksum(sentence: str) -> str:
    """
    Calculate NMEA 0183 checksum for a sentence.

    Args:
        sentence: NMEA sentence without $ prefix or *checksum suffix

    Returns:
        Two-character hex checksum (uppercase)

    Examples:
        >>> calculate_checksum("GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,47.0,M,,")
        '47'
    """
    checksum = 0
    for char in sentence:
        checksum ^= ord(char)
    return f"{checksum:02X}"


def validate_checksum(sentence: str) -> bool:
    """
    Validate NMEA 0183 sentence checksum.

    Args:
        sentence: Complete NMEA sentence with $ prefix and *checksum suffix
                  e.g., "$GPGGA,...*47"

    Returns:
        True if checksum is valid, False otherwise

    Examples:
        >>> validate_checksum("$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,47.0,M,,*47")
        True
        >>> validate_checksum("$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,47.0,M,,*46")
        False
    """
    if not sentence.startswith("$") and not sentence.startswith("!"):
        return False

    if "*" not in sentence:
        return False

    # Split at * to separate content and checksum
    parts = sentence.split("*")
    if len(parts) != 2:
        return False

    # Remove $ or ! prefix and calculate checksum on the content
    content = parts[0][1:]
    provided_checksum = parts[1][:2].upper()  # Take first 2 chars, uppercase

    calculated = calculate_checksum(content)
    return calculated == provided_checksum


def extract_checksum(sentence: str) -> str | None:
    """
    Extract checksum from NMEA sentence.

    Args:
        sentence: Complete NMEA sentence

    Returns:
        Two-character hex checksum (uppercase), or None if not found

    Examples:
        >>> extract_checksum("$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,47.0,M,,*47")
        '47'
    """
    if "*" not in sentence:
        return None

    parts = sentence.split("*")
    if len(parts) != 2:
        return None

    return parts[1][:2].upper()


def add_checksum(sentence: str) -> str:
    """
    Add checksum to NMEA sentence.

    Args:
        sentence: NMEA sentence with $ prefix but without checksum
                  e.g., "$GPGGA,123519,..."

    Returns:
        Complete sentence with checksum

    Examples:
        >>> add_checksum("$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,47.0,M,,")
        '$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,47.0,M,,*47'
    """
    if not sentence.startswith("$") and not sentence.startswith("!"):
        raise ValueError("Sentence must start with $ or !")

    # Remove existing checksum if present
    if "*" in sentence:
        sentence = sentence.split("*")[0]

    # Calculate checksum on content (without $ prefix)
    content = sentence[1:]
    checksum = calculate_checksum(content)

    return f"{sentence}*{checksum}"
