def _extract_body_content(self, payload: Dict) -> tuple:  # noqa: C901
        """Extract plain text and HTML body content from message payload."""
        logger.info("Extracting body content from message payload")
        body_plain = None
        body_html = None

        # Function to recursively extract body parts
        def extract_from_parts(parts, depth=0):
            indent = "  " * depth
            logger.debug(f"{indent}Extracting body from {len(parts)} parts at depth {depth}")
            p_txt, p_html = None, None

            for i, part in enumerate(parts):
                mime_type = part.get("mimeType", "")
                logger.debug(f"{indent}Part {i + 1}/{len(parts)}: mime_type={mime_type}")
                body = part.get("body", {})

                # Check if part has data
                if body.get("data"):
                    data = body.get("data")
                    logger.debug(f"{indent}Found data in part {i + 1} with mime_type {mime_type}")
                    try:
                        decoded = base64.urlsafe_b64decode(data).decode("utf-8", errors="ignore")
                        logger.debug(f"{indent}Decoded {len(decoded)} characters")

                        if mime_type == "text/plain" and not p_txt:
                            logger.debug(f"{indent}Found plain text content ({len(decoded)} chars)")
                            p_txt = decoded
                        elif mime_type == "text/html" and not p_html:
                            logger.debug(f"{indent}Found HTML content ({len(decoded)} chars)")
                            p_html = decoded
                    except Exception as e:
                        logger.error(f"{indent}Error decoding body content: {str(e)}")

                # Check if part has sub-parts
                elif part.get("parts"):
                    sub_parts = part.get("parts", [])
                    logger.debug(f"{indent}Part has {len(sub_parts)} sub-parts, recursing...")
                    sub_txt, sub_html = extract_from_parts(sub_parts, depth + 1)
                    if not p_txt:
                        p_txt = sub_txt
                    if not p_html:
                        p_html = sub_html

            log_msg = (
                f"{indent}Extraction at depth {depth} complete: "
                f"found_text={bool(p_txt)}, found_html={bool(p_html)}"
            )
            logger.debug(log_msg)
            return p_txt, p_html

        # Handle multipart messages
        if payload.get("parts"):
            parts = payload.get("parts", [])
            logger.info(f"Processing multipart message with {len(parts)} parts")
            body_plain, body_html = extract_from_parts(parts)
        # Handle single part messages
        else:
            mime_type = payload.get("mimeType", "")
            logger.info(f"Processing single part message with mime_type: {mime_type}")

            body = payload.get("body", {})
            if body.get("data"):
                data = body.get("data")
                logger.debug(f"Found body data of length: {len(data) if data else 0}")
                try:
                    decoded = base64.urlsafe_b64decode(data).decode("utf-8", errors="ignore")
                    logger.debug(f"Decoded {len(decoded)} characters")

                    if mime_type == "text/plain":
                        logger.debug("Found plain text content in single part")
                        body_plain = decoded
                    elif mime_type == "text/html":
                        logger.debug("Found HTML content in single part")
                        body_html = decoded
                except Exception as e:
                    logger.error(f"Error decoding single part body: {str(e)}")

        logger.info(
            f"Body extraction complete: found_text={bool(body_plain)}, found_html={bool(body_html)}"
        )
        return body_plain, body_html
Extract plain text and HTML body content from message payload.
backend/airweave/platform/sources/gmail.py