Improve; import re
from difflib import SequenceMatcher


def extract_and_append_13c_data(name_formula_list, text_block, debug=False, min_ratio=0.85):
    """
    Final, robust function to accurately find and extract 13C NMR data.

    Key Fixes:
    - A resilient block-splitting method that correctly handles all header formats, including irregular ones.
    - Smarter name extraction to parse known difficult entries.
    """

    def normalize_name(name):
        """A simple, safe normalization function."""
        # Standardize names to lowercase and handle different dash characters.
        return name.lower().replace('–', '-').replace('—', '-').replace('\t', ' ').strip()

    def split_into_compound_blocks(text):
        """
        Splits the text into blocks by finding all possible compound headers first.
        This method is highly robust against formatting inconsistencies.
        """
        # 1. Find the starting character index of every line that contains a compound ID like (3a), (3L), etc.
        #    This pattern is the most reliable marker for a new entry.
        indices = [m.start() for m in re.finditer(r'\n[^\n]*?\([\w\d-]+\)', text)]

        # 2. Add the start of the text (index 0) to the list of starting points.
        if 0 not in indices:
            indices.insert(0, 0)

        # 3. Slice the main text into blocks using the found indices.
        blocks = []
        for i in range(len(indices)):
            start_index = indices[i]
            end_index = indices[i + 1] if i + 1 < len(indices) else len(text)
            block_text = text[start_index:end_index].strip()

            # 4. Only keep blocks that contain NMR data to filter out irrelevant sections.
            if block_text and "NMR" in block_text:
                blocks.append(block_text)

        return blocks

    def get_name_from_block(block):
        """
        Extracts the clean compound name from a block's header,
        with special handling for known malformed entries.
        """
        header_lines = block.split('\n')
        first_line = header_lines[0].strip()

        # Handle the known malformed entry (3L) by reconstructing its name manually.
        if '(3L)' in first_line:
            # The name is split across two lines with extra tabs.
            part1 = re.sub(r'\s*\([\w\d-]+\)\s*', ' ', first_line).strip()
            part2 = header_lines[1].strip()
            return f"{part1} {part2}"

        # For all other compounds, the name is on the first line before the parenthetical ID.
        name = re.sub(r'\s*\([\w\d-]+\)\d*$', '', first_line).strip()
        return name

    def extract_13c_from_block(block):
        """
        Extracts 13C NMR data, correctly handling data followed by "HRMS" on the same line.
        """
        # This regex finds the 13C NMR data and stops before the next capital-letter acronym (like HRMS).
        match = re.search(r'13C\{1H\}NMR.*?MHz\)\s*:?\s*δ?\s*([\d\s.,-]+?)(?=\s[A-Z]{3,}|$)', block,
                          re.DOTALL | re.IGNORECASE)

        if match:
            data_str = match.group(1)
            numbers = re.findall(r'-?\d+\.\d+', data_str)
            if numbers:
                return numbers
        return []

    # --- Main Function Logic ---

    compound_blocks = split_into_compound_blocks(text_block)
    results = []

    for entry in name_formula_list:
        target_name = entry[0]
        if not target_name or '.' in target_name:
            results.append(entry + [0, ""])
            continue

        normalized_target_name = normalize_name(target_name)

        best_match = {"score": 0, "block": None, "name": ""}

        for block in compound_blocks:
            block_name = get_name_from_block(block)
            normalized_block_name = normalize_name(block_name)

            if not normalized_block_name:
                continue

            score = SequenceMatcher(None, normalized_target_name, normalized_block_name).ratio()

            if score > best_match["score"]:
                best_match["score"] = score
                best_match["block"] = block
                best_match["name"] = block_name

        count = 0
        csv = ""

        if best_match["score"] >= min_ratio and best_match["block"]:
            shifts = extract_13c_from_block(best_match["block"])
            if shifts:
                count = len(shifts)
                csv = ", ".join(shifts)

        results.append(entry + [count, csv])

    return results