# sheets/services/halfyear_calc.py
from __future__ import annotations
from typing import Dict, Any
from decimal import Decimal
from sheets.models import (
    Client, SecondTableEntry, ExcelEntry, 
     MonthlySheet, Cell, MonthlySummary)
from django.db.models import Sum
from django.db.models.functions import Coalesce
from django.db.models import DecimalField, Value
HALFYEAR_CLIENTS = ["AG Vogel", "AG Halfm", "IKP"]
TR_RUECKF_FLUESSIG_ROW = 2     
TR_BESTAND_KANNEN_ROW  = 5 
GASBESTAND_ROW_INDEX = 9       
GASBESTAND_COL_NM3 =  3      

# In top_left / top_right, "Bestand in Kannen-1 (Lit. L-He)" is row_index 5
BESTAND_KANNEN_ROW_INDEX = 5
HALFYEAR_RIGHT_CLIENTS = [
    "Dr. Fohrer",
    "AG Buntk.",
    "AG Alff",
    "AG Gutfl.",
    "M3 Thiele",
    "M3 Buntkowsky",
    "M3 Gutfleisch",
    "Merck"
]
BOTTOM1_COL_VOLUME = 0
BOTTOM1_COL_BAR    = 1
BOTTOM1_COL_KORR   = 2
BOTTOM1_COL_NM3    = 3
BOTTOM1_COL_LHE    = 4
BOTTOM2_ROW_ANLAGE = 0
BOTTOM2_COL_G39 = 0   # "Gefäss 2,5" (cell id shows column_index=0)
BOTTOM2_COL_I39 = 1   # "Gefäss 1,0" (cell id shows column_index=1)
BOTTOM2_ROW_INPUTS = {
    "g39": (0, 0),  # row_index=0, column_index=0  (your G39)
    "i39": (0, 1),  # row_index=0, column_index=1  (your I39)
}
FACTOR_NM3_TO_LHE = Decimal("0.75")
RIGHT_CLIENT_INDEX = {name: idx for idx, name in enumerate(HALFYEAR_RIGHT_CLIENTS)}
def get_top_right_value(sheet, client_name: str, row_index: int) -> Decimal:
    """
    Read a numeric value from the top_right table of a MonthlySheet for
    a given client (by column) and row_index.

    top_right cells are keyed by (sheet, table_type='top_right',
    row_index, column_index), where column_index is the position of the
    client in HALFYEAR_RIGHT_CLIENTS.
    """
    if sheet is None:
        return Decimal('0')

    col_index = RIGHT_CLIENT_INDEX.get(client_name)
    if col_index is None:
        return Decimal('0')

    cell = Cell.objects.filter(
        sheet=sheet,
        table_type='top_right',
        row_index=row_index,
        column_index=col_index,
    ).first()

    if cell is None or cell.value in (None, ''):
        return Decimal('0')

    try:
        return Decimal(str(cell.value))
    except Exception:
        return Decimal('0')

def get_bottom2_value(sheet, row_index: int, col_index: int) -> Decimal:
    """Get numeric value from bottom_2 or 0 if missing."""
    if sheet is None:
        return Decimal("0")
    cell = Cell.objects.filter(
        sheet=sheet,
        table_type="bottom_2",
        row_index=row_index,
        column_index=col_index,
    ).first()
    if cell is None or cell.value in (None, ""):
        return Decimal("0")
    try:
        return Decimal(str(cell.value))
    except Exception:
        return Decimal("0")
def get_bottom1_value(sheet, row_index: int, col_index: int) -> Decimal:
    """Get a numeric value from bottom_1, or 0 if missing."""
    if sheet is None:
        return Decimal('0')

    cell = Cell.objects.filter(
        sheet=sheet,
        table_type='bottom_1',
        row_index=row_index,
        column_index=col_index,
    ).first()

    if cell is None or cell.value in (None, ''):
        return Decimal('0')

    try:
        return Decimal(str(cell.value))
    except Exception:
        return Decimal('0')
def get_top_left_value(sheet, client_name: str, row_index: int) -> Decimal:
    """
    Read a numeric value from the top_left table for a given month, client and row.
    Does NOT use column_index, because top_left is keyed only by client + row_index.
    """
    if sheet is None:
        return Decimal('0')

    client_obj = Client.objects.filter(name=client_name).first()
    if not client_obj:
        return Decimal('0')

    cell = Cell.objects.filter(
        sheet=sheet,
        table_type='top_left',
        client=client_obj,
        row_index=row_index,
    ).first()

    if cell is None or cell.value in (None, ''):
        return Decimal('0')

    try:
        return Decimal(str(cell.value))
    except Exception:
        return Decimal('0')
def get_bestand_kannen_for_month(sheet, client_name: str) -> Decimal:
    """
    'B9' in your description: Bestand in Kannen-1 (Lit. L-He)
    For this implementation we take it from top_left row_index = 5 for that client.
    """
    return get_top_left_value(sheet, client_name, row_index=BESTAND_KANNEN_ROW_INDEX)

def pick_sheet_by_gasbestand(window, sheets_by_ym, prev_sheet):
    """
    Returns the last sheet in the window whose Gasbestand (J36, Nm³ column) != 0.
    If none found, returns prev_sheet (Übertrag_Dez__Vorjahr equivalent).
    """
    for (y, m) in reversed(window):
        sheet = sheets_by_ym.get((y, m))
        if not sheet:
            continue
        gasbestand_nm3 = get_bottom1_value(sheet, GASBESTAND_ROW_INDEX, GASBESTAND_COL_NM3)
        if gasbestand_nm3 != 0:
            return sheet
    return prev_sheet
# NEW: clients for the top-right half-year table


def build_halfyear_window(interval_year: int, start_month: int):
    """
    Build a list of (year, month) for the 6-month interval, possibly crossing into the next year.
    Example: (2025, 10) -> [(2025,10), (2025,11), (2025,12), (2026,1), (2026,2), (2026,3)]
    """
    window = []
    for offset in range(6):
        total_index = (start_month - 1) + offset  # 0-based
        y = interval_year + (total_index // 12)
        m = (total_index % 12) + 1
        window.append((y, m))
    return window
# Import ONLY models + pure helpers here
def sum_right_row_without_duplicates(label: str, clients_right: list[str], values: list):
    """
    For specific rows, clients are logically merged, so we must only count one copy.
    """
    # rows where the PAIRS are merged:
    # - Bestand in Kannen-1
    # - Summe Bestand
    # - Best. in Kannen Vormonat
    merged_pair_labels = {
    "Bestand in Kannen-1 (Lit. L-He)",
    "Summe Bestand (Lit. L-He)",
    "Best. in Kannen Vormonat (Lit. L-He)",
    "Verbraucherverluste (Liter L-He)",

    # ✅ Sammel is also duplicated for the merged PAIRS (Fohrer+Buntk, Alff+Gutfl)
    "Sammelrückführungen (Lit. L-He)",
    "Sammelrückführung (Lit. L-He)",  # safety (singular)
}

    merged_m3_labels = {
        # ✅ Sammel is duplicated for the merged M3 triple
        "Sammelrückführungen (Lit. L-He)",
        "Sammelrückführung (Lit. L-He)",  # safety (singular)
    }

    skip_indices = set()

    # skip second column of each merged PAIR
    if label in merged_pair_labels:
        for right_name in ("AG Buntk.", "AG Gutfl."):
            if right_name in clients_right:
                skip_indices.add(clients_right.index(right_name))

    # skip 2nd+3rd of the merged TRIPLE
    if label in merged_m3_labels:
        for name in ("M3 Buntkowsky", "M3 Gutfleisch"):
            if name in clients_right:
                skip_indices.add(clients_right.index(name))

    total = Decimal("0")
    for i, v in enumerate(values):
        if i in skip_indices:
            continue
        if v in (None, ""):
            continue
        total += Decimal(str(v).replace(",", "."))
    return total
def compute_halfyear_context(interval_year: int, interval_start: int) -> Dict[str, Any]:
    """
    Returns a context dict with the SAME keys your current halfyear_balance.html expects.
    """
        # ✅ Paste the pure calculation logic here in Step 2
    window = build_halfyear_window(interval_year, interval_start)
    # window = [(y1, m1), (y2, m2), ..., (y6, m6)]

    # (Year, month) of the first month
    start_year, start_month = window[0]

    # Previous month (for "Stand ... (Vorjahr)" and "Best. in Kannen Vormonat")
    prev_total_index = (start_month - 1) - 1  # one month back, 0-based
    if prev_total_index >= 0:
        prev_year = start_year + (prev_total_index // 12)
        prev_month = (prev_total_index % 12) + 1
    else:
        prev_year = start_year - 1
        prev_month = 12

    # Load MonthlySheet objects for the window and for the previous month
    sheets_by_ym = {}
    for (y, m) in window:
        sheet = MonthlySheet.objects.filter(year=y, month=m).first()
        sheets_by_ym[(y, m)] = sheet

    prev_sheet = MonthlySheet.objects.filter(year=prev_year, month=prev_month).first()
    def pick_bottom2_from_window(window, sheets_by_ym, prev_sheet):
        # choose sheet (same logic you already use)
        chosen = None
        for (y, m) in reversed(window):
            s = sheets_by_ym.get((y, m))
            # use your existing condition for choosing month
            if s:
                chosen = s
                break
        if chosen is None:
            chosen = prev_sheet

        # Now read the two inputs safely
        bottom2_inputs = {}
        for key, (row_idx, col_idx) in BOTTOM2_ROW_INPUTS.items():
            bottom2_inputs[key] = get_bottom2_value(chosen, row_idx, col_idx)

        return chosen, bottom2_inputs


    chosen_sheet_bottom2, bottom2_inputs = pick_bottom2_from_window(window, sheets_by_ym, prev_sheet)

    # ----------------------------
    # HALF-YEAR BOTTOM TABLE 1 (Bilanz) - Read only
    # ----------------------------
    chosen_sheet_bottom1 = pick_sheet_by_gasbestand(window, sheets_by_ym, prev_sheet)

    # define which bottom_1 row_index corresponds to Excel rows 27..35
    # If  bottom_1 starts at Excel row 27 => row_index 0 == Excel 27
    # then row_index = excel_row - 27
    BOTTOM1_EXCEL_START_ROW = 27

    bottom1_excel_rows = list(range(27, 37)) # 27..36
    BOTTOM1_LABELS = [
    "Batterie 1",
    "2",
    "3",
    "4",
    "5",
    "Batterie Links",
    "2 Bündel",
    "2 Ballone",
    "Reingasspeicher",
    "Gasbestand",
    ]

    BOTTOM1_VOLUMES = [
        Decimal("2.4"),
        Decimal("5.1"),
        Decimal("4.0"),
        Decimal("1.0"),
        Decimal("4.0"),
        Decimal("0.6"),
        Decimal("1.2"),
        Decimal("20.0"),
        Decimal("5.0"),
        None,  # Gasbestand row has no volume
    ]
    nm3_sum_27_35 = Decimal("0")
    lhe_sum_27_35 = Decimal("0")
    bottom1_rows = []

    for excel_row in bottom1_excel_rows:
        row_index = excel_row - BOTTOM1_EXCEL_START_ROW

        chosen_sheet_bottom1 = None
        for (y, m) in reversed(window):
            s = sheets_by_ym.get((y, m))
            gasbestand = get_bottom1_value(s, GASBESTAND_ROW_INDEX, GASBESTAND_COL_NM3)  # J36 (Nm3)
            if gasbestand != 0:
                chosen_sheet_bottom1 = s
                break

        if chosen_sheet_bottom1 is None:
            chosen_sheet_bottom1 = prev_sheet

        # Normal rows (27..35): read from chosen sheet and accumulate sums
        if excel_row != 36:
            nm3_val = get_bottom1_value(chosen_sheet_bottom1, row_index, BOTTOM1_COL_NM3)
            lhe_val = get_bottom1_value(chosen_sheet_bottom1, row_index, BOTTOM1_COL_LHE)

            nm3_sum_27_35 += nm3_val
            lhe_sum_27_35 += lhe_val

            bottom1_rows.append({
                "label": BOTTOM1_LABELS[row_index],
                "volume": BOTTOM1_VOLUMES[row_index],
                "bar": get_bottom1_value(chosen_sheet_bottom1, row_index, BOTTOM1_COL_BAR),
                "korr": get_bottom1_value(chosen_sheet_bottom1, row_index, BOTTOM1_COL_KORR),
                "nm3": nm3_val,
                "lhe": lhe_val,
            })

        # Gasbestand row (36): show sums (J36 = SUM(J27:J35), K36 = SUM(K27:K35))
        else:
            bottom1_rows.append({
                "label": "Gasbestand",
                "volume": "",
                "bar": "",
                "korr": "",
                "nm3": nm3_sum_27_35,
                "lhe": lhe_sum_27_35,
            })
        # ------------------------------------------------------------
    # Bottom Table 2 (Halbjahres Bilanz) – server-side recalcBottom2()
    # ------------------------------------------------------------

    FACTOR_BT2 = Decimal("0.75")

    # 1) Helper: pick last-nonzero value of bottom_2 row0 col0/col1 from the window (fallback: prev_sheet)
    def pick_last_nonzero_bottom2(row_index: int, col_index: int) -> Decimal:
        # Scan from last month in window backwards
        for (y, m) in reversed(window):
            s = sheets_by_ym.get((y, m))
            if not s:
                continue
            v = get_bottom2_value(s, row_index, col_index)
            if v is not None and v != 0:
                return v
        # fallback to month before window
        v_prev = get_bottom2_value(prev_sheet, row_index, col_index)
        return v_prev if v_prev is not None else Decimal("0")

    # 2) K38 comes from Overall Summary: "Summe Bestand (Lit. L-He)"
    #    Find it from your already built overall summary rows list.

    k38 = Decimal("0")
    j38 = Decimal("0")
    # 3) Inputs G39 / I39 (picked from last non-zero month in window)
    g39 = pick_last_nonzero_bottom2(row_index=0, col_index=0)  # G39
    i39 = pick_last_nonzero_bottom2(row_index=0, col_index=1)  # I39

    k39 = (g39 or Decimal("0")) + (i39 or Decimal("0"))
    j39 = k39 * FACTOR_BT2

    # 4) +Kaltgas (row 40)
    # JS:
    # g40 = (2500 - g39)/100*10
    # i40 = (1000 - i39)/100*10
    g40 = None
    i40 = None
    if g39 is not None:
        g40 = (Decimal("2500") - g39) / Decimal("100") * Decimal("10")
    if i39 is not None:
        i40 = (Decimal("1000") - i39) / Decimal("100") * Decimal("10")

    k40 = (g40 or Decimal("0")) + (i40 or Decimal("0"))
    j40 = k40 * FACTOR_BT2

    # 5) Bestand flüssig He (row 43)
    k43 = (
    (k38 or Decimal("0")) +
    (k39 or Decimal("0")) +
    (k40 or Decimal("0"))
    )   
    j43 = k43 * FACTOR_BT2

    # 6) Gesamtbestand neu (row 44) = Gasbestand(Lit) from Bottom Table 1 + k43
    gasbestand_lit = Decimal("0")
    for r in bottom1_rows:
        if (r.get("label") or "").strip().startswith("Gasbestand"):
            gasbestand_lit = r.get("lhe") or Decimal("0")
            break

    k44 = (gasbestand_lit or Decimal("0")) + (k43 or Decimal("0"))
    j44 = k44 * FACTOR_BT2

    bottom2 = {
        "j38": j38, "k38": k38,
        "g39": g39, "i39": i39, "j39": j39, "k39": k39,
        "g40": g40, "i40": i40, "j40": j40, "k40": k40,
        "j43": j43, "k43": k43,
        "j44": j44, "k44": k44,
    }

    # ------------------------------------------------------------------
    # 2) LEFT TABLE (your existing, working logic)
    # ------------------------------------------------------------------
    HALFYEAR_CLIENTS_LEFT = ["AG Vogel", "AG Halfm", "IKP"]

    # We'll collect client-wise values first for clarity.
    client_data_left = {name: {} for name in HALFYEAR_CLIENTS_LEFT}

    # --- Row B3: Stand der Gaszähler (Nm³)
    # = MAX(B3 from previous month, and B3 from each of the 6 months in the window)
    # row_index 0 in top_left = "Stand der Gaszähler (Nm³)"
    months_for_max = [(prev_year, prev_month)] + window

    for cname in HALFYEAR_CLIENTS_LEFT:
        max_val = Decimal('0')
        for (y, m) in months_for_max:
            sheet = sheets_by_ym.get((y, m))
            if sheet is None and (y, m) == (prev_year, prev_month):
                sheet = prev_sheet
            val_b3 = get_top_left_value(sheet, cname, row_index=0)
            if val_b3 > max_val:
                max_val = val_b3
        client_data_left[cname]['stand_gas'] = max_val

    # --- Row B4: Stand der Gaszähler (Vorjahr) (Nm³) -> previous month same row ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        val_b4 = get_top_left_value(prev_sheet, cname, row_index=0)
        client_data_left[cname]['stand_gas_prev'] = val_b4

    # --- Row B5: Gasrückführung (Nm³) = B3 - B4 ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        b3 = client_data_left[cname]['stand_gas']
        b4 = client_data_left[cname]['stand_gas_prev']
        client_data_left[cname]['gasrueckf'] = b3 - b4

    # --- Row B6: Rückführung flüssig (Lit. L-He) = B5 / 0.75 ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        b5 = client_data_left[cname]['gasrueckf']
        client_data_left[cname]['rueckf_fluessig'] = (b5 / Decimal('0.75')) if b5 != 0 else Decimal('0')

    # --- Row B7: Sonderrückführungen (Lit. L-He) = sum over 6 months of that row ---
    # That row index is 4 in your top_left table.
    for cname in HALFYEAR_CLIENTS_LEFT:
        sonder_total = Decimal('0')
        for (y, m) in window:
            sheet = sheets_by_ym.get((y, m))
            if sheet:
                sonder_total += get_top_left_value(sheet, cname, row_index=4)
        client_data_left[cname]['sonder'] = sonder_total

    # --- Row B8: Bestand in Kannen-1 (Lit. L-He) ---
    # Excel-style logic with Gasbestand (J36) and fallback to previous month.
    for cname in HALFYEAR_CLIENTS_LEFT:
        chosen_value = None

        # Go from last month (window[5]) backwards to first (window[0])
        for (y, m) in reversed(window):
            sheet = sheets_by_ym.get((y, m))
            gasbestand = get_bottom1_value(sheet, GASBESTAND_ROW_INDEX, GASBESTAND_COL_NM3)
            if gasbestand != 0:
                chosen_value = get_bestand_kannen_for_month(sheet, cname)
                break

        # If still None -> use previous month (Übertrag_Dez__Vorjahr equivalent)
        if chosen_value is None:
            sheet_prev = prev_sheet
            chosen_value = get_bestand_kannen_for_month(sheet_prev, cname)

        client_data_left[cname]['bestand_kannen'] = chosen_value if chosen_value is not None else Decimal('0')

    # --- Row B9: Summe Bestand (Lit. L-He) = equal to previous row ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        client_data_left[cname]['summe_bestand'] = client_data_left[cname]['bestand_kannen']

    # --- Row B10: Best. in Kannen Vormonat (Lit. L-He)
    # = Bestand in Kannen-1 from the month BEFORE the window (prev_year, prev_month)
    for cname in HALFYEAR_CLIENTS_LEFT:
        client_data_left[cname]['best_kannen_vormonat'] = get_bestand_kannen_for_month(prev_sheet, cname)

    # --- Row B13: Bezug (Liter L-He) ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        total_bezug = Decimal('0')
        for (y, m) in window:
            qs = SecondTableEntry.objects.filter(
                client__name=cname,
                date__year=y,
                date__month=m,
            ).aggregate(
                total=Coalesce(Sum('lhe_output'), Value(0, output_field=DecimalField()))
            )
            total_bezug += Decimal(str(qs['total']))
        client_data_left[cname]['bezug'] = total_bezug

    # --- Row B14: Rückführ. Soll (Lit. L-He) = Bezug - Summe Bestand + Best. in Kannen Vormonat ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        b13 = client_data_left[cname]['bezug']
        b11 = client_data_left[cname]['summe_bestand']
        b12 = client_data_left[cname]['best_kannen_vormonat']
        client_data_left[cname]['rueckf_soll'] = b13 - b11 + b12

   # --- Row B15: Verluste (Soll-Rückf.) (Lit. L-He)
    # AG Vogel, AG Halfm: B14 - B6
    # IKP:               B14 - B6 - B7 (Sonderrückführungen)
    for cname in HALFYEAR_CLIENTS_LEFT:
        b14 = client_data_left[cname]['rueckf_soll']
        b6 = client_data_left[cname]['rueckf_fluessig']

        if (cname or "").strip() == "IKP":
            b7 = client_data_left[cname].get('sonder', Decimal('0'))
            client_data_left[cname]['verluste'] = b14 - b6 - b7
        else:
            client_data_left[cname]['verluste'] = b14 - b6
    # --- Row B16: Füllungen warm (Lit. L-He) = sum over 6 months (row_index=11) ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        total_warm = Decimal('0')
        for (y, m) in window:
            sheet = sheets_by_ym.get((y, m))
            total_warm += get_top_left_value(sheet, cname, row_index=11)
        client_data_left[cname]['fuellungen_warm'] = total_warm

    # --- Row B17: Kaltgas Rückgabe (Lit. L-He) = Bezug * 0.06 ---
    factor = Decimal('0.06')
    for cname in HALFYEAR_CLIENTS_LEFT:
        b13 = client_data_left[cname]['bezug']
        client_data_left[cname]['kaltgas_rueckgabe'] = b13 * factor

    # --- Row B18: Verbraucherverluste (Liter L-He) = Verluste - Kaltgas Rückgabe ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        b15 = client_data_left[cname]['verluste']
        b17 = client_data_left[cname]['kaltgas_rueckgabe']
        client_data_left[cname]['verbraucherverluste'] = b15 - b17

    # --- Row B19: % = Verbraucherverluste / Bezug ---
    for cname in HALFYEAR_CLIENTS_LEFT:
        bezug = client_data_left[cname]['bezug']
        verb = client_data_left[cname]['verbraucherverluste']
        if bezug != 0:
            client_data_left[cname]['percent'] = verb / bezug
        else:
            client_data_left[cname]['percent'] = None

    # Build LEFT rows structure
    left_row_defs = [
        ('Stand der Gaszähler (Nm³)', 'stand_gas'),
        ('Stand der Gaszähler (Vorjahr) (Nm³)', 'stand_gas_prev'),
        ('Gasrückführung (Nm³)', 'gasrueckf'),
        ('Rückführung flüssig (Lit. L-He)', 'rueckf_fluessig'),
        ('Sonderrückführungen (Lit. L-He)', 'sonder'),
        ('Bestand in Kannen-1 (Lit. L-He)', 'bestand_kannen'),
        ('Summe Bestand (Lit. L-He)', 'summe_bestand'),
        ('Best. in Kannen Vormonat (Lit. L-He)', 'best_kannen_vormonat'),
        ('Bezug (Liter L-He)', 'bezug'),
        ('Rückführ. Soll (Lit. L-He)', 'rueckf_soll'),
        ('Verluste (Soll-Rückf.) (Lit. L-He)', 'verluste'),
        ('Füllungen warm (Lit. L-He)', 'fuellungen_warm'),
        ('Kaltgas Rückgabe (Lit. L-He) – Faktor', 'kaltgas_rueckgabe'),
        ('Verbraucherverluste (Liter L-He)', 'verbraucherverluste'),
        ('%', 'percent'),
    ]

    rows_left = []
    for label, key in left_row_defs:
        values = [client_data_left[cname][key] for cname in HALFYEAR_CLIENTS_LEFT]
        if key == 'percent':
            total_bezug = sum((client_data_left[c]['bezug'] for c in HALFYEAR_CLIENTS_LEFT), Decimal('0'))
            total_verb = sum((client_data_left[c]['verbraucherverluste'] for c in HALFYEAR_CLIENTS_LEFT), Decimal('0'))
            total = (total_verb / total_bezug) if total_bezug != 0 else None
        else:
            total = sum((v for v in values if v is not None), Decimal('0'))
        rows_left.append({
            'label': label,
            'values': values,
            'total': total,
            'is_percent': key == 'percent',
        })

    # ------------------------------------------------------------------
    # 3) RIGHT TABLE (top-right half-year aggregation)
    # ------------------------------------------------------------------
    RIGHT_CLIENTS = HALFYEAR_RIGHT_CLIENTS  # for brevity

    right_data = {name: {} for name in RIGHT_CLIENTS}

    # --- Bezug (Liter L-He) for each right client (same as for left) ---
    for cname in RIGHT_CLIENTS:
        total_bezug = Decimal('0')
        for (y, m) in window:
            qs = SecondTableEntry.objects.filter(
                client__name=cname,
                date__year=y,
                date__month=m,
            ).aggregate(
                total=Coalesce(Sum('lhe_output'), Value(0, output_field=DecimalField()))
            )
            total_bezug += Decimal(str(qs['total']))
        right_data[cname]['bezug'] = total_bezug
    def find_bestand_from_window(reference_client: str) -> Decimal:
        """
        Implements:
        WENN(last_month!J36=0; WENN(prev_month!J36=0; ...; prev_sheet!<col>9); last_month!<col>9)
        reference_client decides which column (L/N/P/Q/R) we read from monthly top_right row_index=5.
        """
        # scan backward through window
        for (y, m) in reversed(window):
            sh = sheets_by_ym.get((y, m))
            if not sh:
                continue
            gasbestand = get_bottom1_value(sh, GASBESTAND_ROW_INDEX, GASBESTAND_COL_NM3)
            if gasbestand != 0:
                return get_top_right_value(sh, reference_client, TR_BESTAND_KANNEN_ROW)

        # fallback to previous month (Übertrag_Dez__Vorjahr equivalent)
        return get_top_right_value(prev_sheet, reference_client, TR_BESTAND_KANNEN_ROW)

    # Fohrer+Buntk merged: BOTH use Fohrer column (L9)
    val_L = find_bestand_from_window("Dr. Fohrer")
    right_data["Dr. Fohrer"]["bestand_kannen"] = val_L
    right_data["AG Buntk."]["bestand_kannen"]  = val_L

    # Alff+Gutfl merged: BOTH use Alff column (N9)
    val_N = find_bestand_from_window("AG Alff")
    right_data["AG Alff"]["bestand_kannen"]   = val_N
    right_data["AG Gutfl."]["bestand_kannen"] = val_N

    # M3 each uses its own column (P9/Q9/R9)
    right_data["M3 Thiele"]["bestand_kannen"]      = find_bestand_from_window("M3 Thiele")
    right_data["M3 Buntkowsky"]["bestand_kannen"]  = find_bestand_from_window("M3 Buntkowsky")
    right_data["M3 Gutfleisch"]["bestand_kannen"]  = find_bestand_from_window("M3 Gutfleisch")
    # Helper for pair shares (L13/($L13+$M13), etc.)
    def pair_share(c1, c2):
        total = right_data[c1]['bezug'] + right_data[c2]['bezug']
        if total == 0:
            return (Decimal('0'), Decimal('0'))
        return (
            right_data[c1]['bezug'] / total,
            right_data[c2]['bezug'] / total,
        )

    # --- "Stand der Gaszähler (Vorjahr) (Nm³)" row: share based on Bezug ---
    # Dr. Fohrer / AG Buntk.
    s_fohrer, s_buntk = pair_share("Dr. Fohrer", "AG Buntk.")
    right_data["Dr. Fohrer"]['stand_prev_share'] = s_fohrer
    right_data["AG Buntk."]['stand_prev_share'] = s_buntk

    # AG Alff / AG Gutfl.
    s_alff, s_gutfl = pair_share("AG Alff", "AG Gutfl.")
    right_data["AG Alff"]['stand_prev_share'] = s_alff
    right_data["AG Gutfl."]['stand_prev_share'] = s_gutfl

    # M3 Thiele / M3 Buntkowsky / M3 Gutfleisch → empty in Excel → None
    for cname in ["M3 Thiele", "M3 Buntkowsky", "M3 Gutfleisch"]:
        right_data[cname]['stand_prev_share'] = None

    # --- Rückführung flüssig per month (raw sums) ---
    # top_right row_index=2 is "Rückführung flüssig (Lit. L-He)"

    # --- Sonderrückführungen (row_index=3 in top_right) ---
    for cname in RIGHT_CLIENTS:
        sonder_total = Decimal('0')
        for (y, m) in window:
            sheet = sheets_by_ym.get((y, m))
            if sheet:
                sonder_total += get_top_right_value(sheet, cname, row_index=3)
        right_data[cname]['sonder'] = sonder_total

    # --- Sammelrückführung (row_index=4 in top_right), grouped & merged ---
    # Group 1: Dr. Fohrer + AG Buntk.
    group1_total = Decimal('0')
    for (y, m) in window:
        sheet = sheets_by_ym.get((y, m))
        if sheet:
            group1_total += get_top_right_value(sheet, "Dr. Fohrer", row_index=4)
    right_data["Dr. Fohrer"]['sammel'] = group1_total
    right_data["AG Buntk."]['sammel'] = group1_total

    # Group 2: AG Alff + AG Gutfl.
    group2_total = Decimal('0')
    for (y, m) in window:
        sheet = sheets_by_ym.get((y, m))
        if sheet:
            group2_total += get_top_right_value(sheet, "AG Alff", row_index=4)
    right_data["AG Alff"]['sammel'] = group2_total
    right_data["AG Gutfl."]['sammel'] = group2_total

    # Group 3: M3 Thiele + M3 Buntkowsky + M3 Gutfleisch
    group3_total = Decimal('0')
    for (y, m) in window:
        sheet = sheets_by_ym.get((y, m))
        if sheet:
            group3_total += get_top_right_value(sheet, "M3 Thiele", row_index=4)
    right_data["M3 Thiele"]['sammel'] = group3_total
    right_data["M3 Buntkowsky"]['sammel'] = group3_total
    right_data["M3 Gutfleisch"]['sammel'] = group3_total
    def safe_div(a: Decimal, b: Decimal) -> Decimal:
        return (a / b) if b != 0 else Decimal("0")
    
        # Merck: Sammelrückführung = total helium input (ExcelEntry.lhe_ges) over the 6-month window
    merck_sammel_total = Decimal("0")
    for (y, m) in window:
        qs = ExcelEntry.objects.filter(
            client__name="Merck",
            date__year=y,
            date__month=m,
        ).aggregate(
            total=Coalesce(Sum("lhe_ges"), Value(0, output_field=DecimalField()))
        )
        merck_sammel_total += Decimal(str(qs["total"]))

    right_data["Merck"]["sammel"] = merck_sammel_total

    # --- Rückführung flüssig (Lit. L-He) for Halbjahres-Bilanz top-right ---
    # Uses your exact formulas.

    # 1) Fohrer / Buntk split by BEZUG share times group SAMMEL (L8)
    L13 = right_data["Dr. Fohrer"]["bezug"]
    M13 = right_data["AG Buntk."]["bezug"]
    L8  = right_data["Dr. Fohrer"]["sammel"]   # merged group total

    den = (L13 + M13)
    right_data["Dr. Fohrer"]["rueckf_fluessig"] = (safe_div(L13, den) * L8) if den != 0 else Decimal("0")
    right_data["AG Buntk."]["rueckf_fluessig"]  = (safe_div(M13, den) * L8) if den != 0 else Decimal("0")

    # 2) Alff / Gutfl split by BEZUG share times group SAMMEL (N8)
    N13 = right_data["AG Alff"]["bezug"]
    O13 = right_data["AG Gutfl."]["bezug"]
    N8  = right_data["AG Alff"]["sammel"]       # merged group total

    den = (N13 + O13)
    right_data["AG Alff"]["rueckf_fluessig"]   = (safe_div(N13, den) * N8) if den != 0 else Decimal("0")
    right_data["AG Gutfl."]["rueckf_fluessig"] = (safe_div(O13, den) * N8) if den != 0 else Decimal("0")

    # 3) M3 Thiele = sum of monthly Rückführung flüssig (monthly top_right row_index=2) over window
    P6_sum = Decimal("0")
    for (y, m) in window:
        sh = sheets_by_ym.get((y, m))
        P6_sum += get_top_right_value(sh, "M3 Thiele", TR_RUECKF_FLUESSIG_ROW)
    right_data["M3 Thiele"]["rueckf_fluessig"] = P6_sum

    # 4) M3 Buntkowsky / M3 Gutfleisch split by BEZUG share times M3-group SAMMEL (P8)
    P13 = right_data["M3 Thiele"]["bezug"]
    Q13 = right_data["M3 Buntkowsky"]["bezug"]
    R13 = right_data["M3 Gutfleisch"]["bezug"]
    P8  = right_data["M3 Thiele"]["sammel"]     # merged group total

    den = (P13 + Q13 + R13)
    right_data["M3 Buntkowsky"]["rueckf_fluessig"] = (safe_div(Q13, den) * P8) if den != 0 else Decimal("0")
    right_data["M3 Gutfleisch"]["rueckf_fluessig"] = (safe_div(R13, den) * P8) if den != 0 else Decimal("0")
    # --- Bestand in Kannen-1 (Lit. L-He) for right table (grouped) ---
    # Use Gasbestand (J36) and fallback logic, but now reading top_right B9 for each group.
    TOP_RIGHT_ROW_BESTAND_KANNEN = TR_BESTAND_KANNEN_ROW  # <-- most likely correct in your setup

    def pick_bestand_top_right(base_client: str) -> Decimal:
        # Go from last month in window backwards: if Gasbestand != 0, use that month's Bestand in Kannen
        for (y, m) in reversed(window):
            sh = sheets_by_ym.get((y, m))
            if not sh:
                continue

            gasbestand = get_bottom1_value(sh, GASBESTAND_ROW_INDEX, GASBESTAND_COL_NM3)
            if gasbestand != 0:
                return get_top_right_value(sh, base_client, TOP_RIGHT_ROW_BESTAND_KANNEN)

        # Fallback to previous month (Übertrag_Dez__Vorjahr equivalent)
        return get_top_right_value(prev_sheet, base_client, TOP_RIGHT_ROW_BESTAND_KANNEN)

    # Group 1 merged (Fohrer + Buntk.)
    g1_best = pick_bestand_top_right("Dr. Fohrer")
    right_data["Dr. Fohrer"]["bestand_kannen"] = g1_best
    right_data["AG Buntk."]["bestand_kannen"] = g1_best

    # Group 2 merged (Alff + Gutfl.)
    g2_best = pick_bestand_top_right("AG Alff")
    right_data["AG Alff"]["bestand_kannen"]   = g2_best
    right_data["AG Gutfl."]["bestand_kannen"] = g2_best

   # Group 3 NOT merged: each M3 client uses its own most recent nonzero Bestand in Kannen-1
    right_data["M3 Thiele"]["bestand_kannen"]      = pick_bestand_top_right("M3 Thiele")
    right_data["M3 Buntkowsky"]["bestand_kannen"]  = pick_bestand_top_right("M3 Buntkowsky")
    right_data["M3 Gutfleisch"]["bestand_kannen"]  = pick_bestand_top_right("M3 Gutfleisch")
    # Merck should stay empty in Bestand in Kannen-1
    right_data["Merck"]["bestand_kannen"] = None 
    right_data["Merck"]["best_kannen_vormonat"] = None   

    # Summe Bestand = same as previous row
    for cname in RIGHT_CLIENTS:
        right_data[cname]['summe_bestand'] = right_data[cname]['bestand_kannen']

    # Best. in Kannen Vormonat (Lit. L-He) from previous month top_right row_index=7
    g1_prev = get_top_right_value(prev_sheet, "Dr. Fohrer", TOP_RIGHT_ROW_BESTAND_KANNEN)
    right_data["Dr. Fohrer"]['best_kannen_vormonat'] = g1_prev
    right_data["AG Buntk."]['best_kannen_vormonat'] = g1_prev

    g2_prev = get_top_right_value(prev_sheet, "AG Alff",    TOP_RIGHT_ROW_BESTAND_KANNEN)
    right_data["AG Alff"]['best_kannen_vormonat'] = g2_prev
    right_data["AG Gutfl."]['best_kannen_vormonat'] = g2_prev


    # Group 1 merged (Fohrer + Buntk.)
    g1_prev = get_top_right_value(prev_sheet, "Dr. Fohrer",  TOP_RIGHT_ROW_BESTAND_KANNEN)
    right_data["Dr. Fohrer"]["best_kannen_vormonat"] = g1_prev
    right_data["AG Buntk."]["best_kannen_vormonat"]  = g1_prev

    # Group 2 merged (Alff + Gutfl.)
    g2_prev = get_top_right_value(prev_sheet, "AG Alff",  TOP_RIGHT_ROW_BESTAND_KANNEN)
    right_data["AG Alff"]["best_kannen_vormonat"]   = g2_prev
    right_data["AG Gutfl."]["best_kannen_vormonat"] = g2_prev

    # Group 3 UNMERGED (each one reads its own cell)
    right_data["M3 Thiele"]["best_kannen_vormonat"]     = get_top_right_value(prev_sheet, "M3 Thiele", TOP_RIGHT_ROW_BESTAND_KANNEN)
    right_data["M3 Buntkowsky"]["best_kannen_vormonat"] = get_top_right_value(prev_sheet, "M3 Buntkowsky", TOP_RIGHT_ROW_BESTAND_KANNEN)
    right_data["M3 Gutfleisch"]["best_kannen_vormonat"] = get_top_right_value(prev_sheet, "M3 Gutfleisch",  TOP_RIGHT_ROW_BESTAND_KANNEN)

    # --- Rückführ. Soll (Lit. L-He) according to your formulas ---

    # Group 1: Dr. Fohrer / AG Buntk.
    total_bestand_1 = right_data["Dr. Fohrer"]['summe_bestand']
    best_vormonat_1 = right_data["Dr. Fohrer"]['best_kannen_vormonat']
    diff1 = total_bestand_1 - best_vormonat_1
    share_fohrer = right_data["Dr. Fohrer"]['stand_prev_share'] or Decimal('0')

    right_data["Dr. Fohrer"]['rueckf_soll'] = (
        right_data["Dr. Fohrer"]['bezug'] - diff1 * share_fohrer
    )
    right_data["AG Buntk."]['rueckf_soll'] = (
        right_data["AG Buntk."]['bezug'] - total_bestand_1 + best_vormonat_1
    )

    # Group 2: AG Alff / AG Gutfl.
    total_bestand_2 = right_data["AG Alff"]['summe_bestand']
    best_vormonat_2 = right_data["AG Alff"]['best_kannen_vormonat']
    diff2 = total_bestand_2 - best_vormonat_2
    share_alff = right_data["AG Alff"]['stand_prev_share'] or Decimal('0')
    share_gutfl = right_data["AG Gutfl."]['stand_prev_share'] or Decimal('0')

    right_data["AG Alff"]['rueckf_soll'] = (
        right_data["AG Alff"]['bezug'] - diff2 * share_alff
    )
    right_data["AG Gutfl."]['rueckf_soll'] = (
        right_data["AG Gutfl."]['bezug'] - diff2 * share_gutfl
    )

    # Group 3: M3 Thiele / M3 Buntkowsky / M3 Gutfleisch
    for cname in ["M3 Thiele", "M3 Buntkowsky", "M3 Gutfleisch"]:
        b13 = right_data[cname]['bezug']
        b12 = right_data[cname]['best_kannen_vormonat']
        b11 = right_data[cname]['summe_bestand']
        # Excel: P13+P12-P11 etc.
        right_data[cname]['rueckf_soll'] = b13 + b12 - b11
    # Merck: only selected rows should have values in Top Right Halbjahresbilanz
    right_data["Merck"]["stand_prev_share"] = None
    right_data["Merck"]["rueckf_fluessig"] = None
    right_data["Merck"]["sonder"] = None
    right_data["Merck"]["bestand_kannen"] = None
    right_data["Merck"]["summe_bestand"] = None
    right_data["Merck"]["best_kannen_vormonat"] = None
    right_data["Merck"]["rueckf_soll"] = None
    right_data["Merck"]["verluste"] = None
    right_data["Merck"]["fuellungen_warm"] = None
    right_data["Merck"]["kaltgas_rueckgabe"] = None
    # --- Verluste (Soll-Rückf.) (Lit. L-He) = B14 - B6 - B7 ---
    for cname in RIGHT_CLIENTS:
        if cname == "Merck":
            right_data[cname]['verluste'] = None
            continue

        b14 = right_data[cname]['rueckf_soll']
        b6 = right_data[cname]['rueckf_fluessig']
        b7 = right_data[cname]['sonder']
        right_data[cname]['verluste'] = b14 - b6 - b7

    # --- Füllungen warm (Lit. L-He) = sum of monthly 'Füllungen warm' (row_index=11 top_right) ---
    for cname in RIGHT_CLIENTS:
        total_warm = Decimal('0')
        for (y, m) in window:
            sheet = sheets_by_ym.get((y, m))
            if sheet:
                total_warm += get_top_right_value(sheet, cname, row_index=11)
        right_data[cname]['fuellungen_warm'] = total_warm

    # --- Kaltgas Rückgabe (Lit. L-He) – Faktor = Bezug * 0.06 ---
    for cname in RIGHT_CLIENTS:
        b13 = right_data[cname]['bezug']
        right_data[cname]['kaltgas_rueckgabe'] = b13 * factor

    # --- Verbraucherverluste (Liter L-He) ---
    for cname in RIGHT_CLIENTS:
        if cname == "Merck":
            bezug = right_data[cname].get("bezug") or Decimal("0")
            sammel = right_data[cname].get("sammel") or Decimal("0")
            right_data[cname]["verbraucherverluste"] = bezug - sammel
        else:
            b15 = right_data[cname]['verluste']
            b17 = right_data[cname]['kaltgas_rueckgabe']
            right_data[cname]['verbraucherverluste'] = b15 - b17

    # --- % = Verbraucherverluste / Bezug ---
    for cname in RIGHT_CLIENTS:
        bezug = right_data[cname].get('bezug') or Decimal("0")
        verb = right_data[cname].get('verbraucherverluste')
        if bezug != 0 and verb is not None:
            right_data[cname]['percent'] = verb / bezug
        else:
            right_data[cname]['percent'] = None

    # Build RIGHT rows structure
    right_row_defs = [
        ('Stand der Gaszähler (Vorjahr) (Nm³)', 'stand_prev_share'),
        # We skip the pure-text "Gasrückführung (Nm³)" line here,
        # because it’s only text (Aufteilung nach Verbrauch / Gaszähler)
        # and easier to render directly in the template if needed.
        ('Rückführung flüssig (Lit. L-He)', 'rueckf_fluessig'),
        ('Sonderrückführungen (Lit. L-He)', 'sonder'),
        ('Sammelrückführung (Lit. L-He)', 'sammel'),
        ('Bestand in Kannen-1 (Lit. L-He)', 'bestand_kannen'),
        ('Summe Bestand (Lit. L-He)', 'summe_bestand'),
        ('Best. in Kannen Vormonat (Lit. L-He)', 'best_kannen_vormonat'),
        ('Bezug (Liter L-He)', 'bezug'),
        ('Rückführ. Soll (Lit. L-He)', 'rueckf_soll'),
        ('Verluste (Soll-Rückf.) (Lit. L-He)', 'verluste'),
        ('Füllungen warm (Lit. L-He)', 'fuellungen_warm'),
        ('Kaltgas Rückgabe (Lit. L-He) – Faktor', 'kaltgas_rueckgabe'),
        ('Verbraucherverluste (Liter L-He)', 'verbraucherverluste'),
        ('%', 'percent'),
    ]

    rows_right = []
    for label, key in right_row_defs:
        values = [right_data[cname].get(key) for cname in RIGHT_CLIENTS]

        if key == 'percent':
            total_bezug = sum((right_data[c]['bezug'] for c in RIGHT_CLIENTS), Decimal('0'))
            total_verb = sum((right_data[c]['verbraucherverluste'] for c in RIGHT_CLIENTS), Decimal('0'))
            total = (total_verb / total_bezug) if total_bezug != 0 else None
        else:
            total = sum((v for v in values if isinstance(v, Decimal)), Decimal('0'))

        rows_right.append({
            'label': label,
            'values': values,
            'total': total,
            'is_percent': key == 'percent',
        })
        SUM_TABLE_ROWS = [
        ("Rückführung flüssig (Lit. L-He)", "rueckf_fluessig"),
        ("Sonderrückführungen (Lit. L-He)", "sonder"),
        ("Sammelrückführungen (Lit. L-He)", "sammel"),
        ("Bestand in Kannen-1 (Lit. L-He)", "bestand_kannen"),
        ("Summe Bestand (Lit. L-He)", "summe_bestand"),
        ("Best. in Kannen Vormonat (Lit. L-He)", "best_kannen_vormonat"),
        ("Bezug (Liter L-He)", "bezug"),
        ("Rückführ. Soll (Lit. L-He)", "rueckf_soll"),
        ("Verluste (Soll-Rückf.) (Lit. L-He)", "verluste"),
        ("Füllungen warm (Lit. L-He)", "fuellungen_warm"),
        ("Kaltgas Rückgabe (Lit. L-He) – Faktor", "kaltgas_rueckgabe"),
        ("Faktor 0.06", "factor_row"),
        ("Verbraucherverluste (Liter L-He)", "verbraucherverluste"),
        ("%", "percent"),
    ]

    RIGHT_GROUPS = {
        "chemie": ["Dr. Fohrer", "AG Buntk."],
        "mawi":   ["AG Alff", "AG Gutfl."],
        "m3":     ["M3 Thiele", "M3 Buntkowsky", "M3 Gutfleisch"],
    }

    RIGHT_ALL = ["Dr. Fohrer", "AG Buntk.", "AG Alff", "AG Gutfl.", "M3 Thiele", "M3 Buntkowsky", "M3 Gutfleisch"]
    LEFT_ALL  = HALFYEAR_CLIENTS_LEFT

    def safe_pct(verb, bez):
        return (verb / bez) if bez != 0 else None
    def sum_right_key(label_for_merge: str, clients: list[str], key: str) -> Decimal:
        vals = [right_data[c].get(key) for c in clients]
        return sum_right_row_without_duplicates(label_for_merge, clients, vals)
    rows_sum = []
    def d(x):
        return x if isinstance(x, Decimal) else Decimal("0")
    for row_index, (label, key) in enumerate(SUM_TABLE_ROWS):

        if key == "factor_row":
            lichtwiese = chemie = mawi = m3 = total = Decimal("0.06")

        elif key == "percent":
            # We want % = Verbraucherverluste / Bezug (for each group)

            # LEFT totals (no merge on left)
            left_bez = sum(d(client_data_left[c].get("bezug")) for c in LEFT_ALL)
            left_verb = sum(d(client_data_left[c].get("verbraucherverluste")) for c in LEFT_ALL)

            # RIGHT totals (must skip merged duplicates!)
            rw_bez = sum(d(right_data[c].get("bezug")) for c in RIGHT_ALL)

            rw_verb = sum_right_key("Verbraucherverluste (Liter L-He)", RIGHT_ALL, "verbraucherverluste")

            lichtwiese = safe_pct(rw_verb, rw_bez)

            # Chemie group (Fohrer+Buntk)
            ch_clients = RIGHT_GROUPS["chemie"]
            ch_bez = sum_right_key("Bezug (Liter L-He)", ch_clients, "bezug")
            ch_verb = sum_right_key("Verbraucherverluste (Liter L-He)", ch_clients, "verbraucherverluste")
            chemie = safe_pct(ch_verb, ch_bez)

            # MaWi group (Alff+Gutfl)
            mw_clients = RIGHT_GROUPS["mawi"]
            mw_bez = sum_right_key("Bezug (Liter L-He)", mw_clients, "bezug")
            mw_verb = sum_right_key("Verbraucherverluste (Liter L-He)", mw_clients, "verbraucherverluste")
            mawi = safe_pct(mw_verb, mw_bez)

            # M3 group (triple)
            m3_clients = RIGHT_GROUPS["m3"]
            m3_bez = sum_right_key("Bezug (Liter L-He)", m3_clients, "bezug")
            m3_verb = sum_right_key("Verbraucherverluste (Liter L-He)", m3_clients, "verbraucherverluste")
            m3 = safe_pct(m3_verb, m3_bez)

            # Overall Σ (%)
            total = safe_pct(left_verb + rw_verb, left_bez + rw_bez)


        else:
            # normal rows = sums (BUT skip duplicates for merged logical cells)
            rw_values = [right_data[c].get(key) for c in RIGHT_ALL]
            lichtwiese = sum_right_row_without_duplicates(label, RIGHT_ALL, rw_values)

            ch_clients = RIGHT_GROUPS["chemie"]
            ch_values = [right_data[c].get(key) for c in ch_clients]
            chemie = sum_right_row_without_duplicates(label, ch_clients, ch_values)

            mw_clients = RIGHT_GROUPS["mawi"]
            mw_values = [right_data[c].get(key) for c in mw_clients]
            mawi = sum_right_row_without_duplicates(label, mw_clients, mw_values)

            m3_clients = RIGHT_GROUPS["m3"]
            m3_values = [right_data[c].get(key) for c in m3_clients]
            m3 = sum_right_row_without_duplicates(label, m3_clients, m3_values)

            left_total = sum(d(client_data_left[c].get(key)) for c in LEFT_ALL)

            # Merck should count ONLY in the overall total, not in Lichtwiese
            merck_val = d(right_data["Merck"].get(key))

            total = left_total + lichtwiese + merck_val

        # ✅ THIS MUST BE OUTSIDE THE IF/ELIF/ELSE
        rows_sum.append({
            "row_index": row_index,
            "label": label,
            "total": total,
            "lichtwiese": lichtwiese,
            "chemie": chemie,
            "mawi": mawi,
            "m3": m3,
            "is_percent": (key == "percent"),
        })

    def find_sum_row(rows, label_startswith: str):
        for r in rows:
            if str(r.get("label", "")).strip().startswith(label_startswith):
                return r
        return None

    summe_bestand_row = find_sum_row(rows_sum, "Summe Bestand")
    k38 = (summe_bestand_row.get("total") if summe_bestand_row else Decimal("0")) or Decimal("0")
    j38 = k38 * Decimal("0.75")
    # --- FIX: now that k38 is known, update bottom2 + recompute dependent rows ---
    bottom2["k38"] = k38
    bottom2["j38"] = j38

    k39 = bottom2.get("k39") or Decimal("0")
    k40 = bottom2.get("k40") or Decimal("0")

    # Row 43: Bestand flüssig He = SUMME(K38:K40)
    k43 = (k38 or Decimal("0")) + k39 + k40
    j43 = k43 * Decimal("0.75")

    bottom2["k43"] = k43
    bottom2["j43"] = j43

    # Row 44: Gesamtbestand neu = Gasbestand(Lit) from bottom table 1 + k43
    gasbestand_lit = Decimal("0")
    for r in bottom1_rows:
        if (r.get("label") or "").strip().startswith("Gasbestand"):
            gasbestand_lit = r.get("lhe") or Decimal("0")
            break

    k44 = gasbestand_lit + k43
    j44 = k44 * Decimal("0.75")

    bottom2["k44"] = k44
    bottom2["j44"] = j44
    def d_or_none(x):
        return x if isinstance(x, Decimal) else None

    # ---- Bottom2: J38/K38 depend on rows_sum (overall summary), so do it HERE ----
    k38 = Decimal("0")
    for r in rows_sum:
        if r.get("label") == "Summe Bestand (Lit. L-He)":
            k38 = r.get("total") or Decimal("0")
            break

    j38 = k38 * FACTOR_NM3_TO_LHE  # 0.75
    bottom2["k38"] = k38
    bottom2["j38"] = j38
    factor = Decimal("0.75")

    # window = the 6-month list you already build in this view: [(y,m), (y,m), ...]
    # bottom2 = dict with "k44" already computed in your view
    # rows_sum = overall sum group rows list (your existing halfyear logic)

    # 1) K46 = K44 from the month BEFORE the global month (interval start)
    start_year = interval_year
    start_month = interval_start  # whatever you named your start month variable

    if start_month == 1:
        prev_year, prev_month = start_year - 1, 12
    else:
        prev_year, prev_month = start_year, start_month - 1

    prev_sheet = MonthlySheet.objects.filter(year=prev_year, month=prev_month).first()

    # This assumes you have MonthlySummary.gesamtbestand_neu_lhe as K44 equivalent.
    # If your field name differs, tell me your MonthlySummary model fields.
    prev_k44 = Decimal("0")
    if prev_sheet:
        prev_sum = MonthlySummary.objects.filter(sheet=prev_sheet).first()
        if prev_sum and prev_sum.gesamtbestand_neu_lhe is not None:
            prev_k44 = Decimal(str(prev_sum.gesamtbestand_neu_lhe))

    # helpers: read bottom_3 values for a given sheet/month
    def get_bottom3_value(sheet, row_index, col_index):
        if not sheet:
            return Decimal("0")
        c = Cell.objects.filter(
            sheet=sheet, table_type="bottom_3",
            row_index=row_index, column_index=col_index
        ).first()
        if not c or c.value in (None, "", "None"):
            return Decimal("0")
        try:
            return Decimal(str(c.value))
        except Exception:
            return Decimal("0")

    # 2) Sum rows across the 6-month window
    g47_sum = Decimal("0")
    i47_sum = Decimal("0")
    j47_sum = Decimal("0")

    g50_sum = Decimal("0")
    i50_sum = Decimal("0")

    for (yy, mm) in window:
        s = MonthlySheet.objects.filter(year=yy, month=mm).first()
        ## Excel row 47 maps to bottom_3 row_index=1 in DB (see monthly_sheet.html)
        g = get_bottom3_value(s, 1, 1)  # G47 editable
        i = get_bottom3_value(s, 1, 2)  # I47 editable

        g47_sum += g
        i47_sum += i

        # In monthly_sheet, J47 is CALCULATED as (G47 + I47), not stored as an editable cell
        j47_sum += (g + i)

        # row 50: G(2), I(4)
        g50_sum += get_bottom3_value(s, 50, 2)
        i50_sum += get_bottom3_value(s, 50, 4)

    # 3) K52 = Verbraucherverlust from overall sum group first column (global Σ)
    k52 = Decimal("0")
    for r in rows_sum:
        label = (r.get("label") or "")
        if label.startswith("Verbraucherverluste"):
            k52 = r.get("total") or Decimal("0")
            break

    # --- apply the SAME monthly formulas, with your overrides ---
    # Row 46
    k46 = prev_k44
    j46 = k46 * factor

    # Row 47
    g47 = g47_sum
    i47 = i47_sum
    j47 = j47_sum
    k47 = (j47 / factor) + g47 if (j47 != 0 or g47 != 0) else Decimal("0")

    # Row 48
    k48 = k46 + k47
    j48 = k48 * factor

    # Row 49 (akt. Monat) -> in halfyear we use current bottom2 K44
    k49 = bottom2.get("k44") or Decimal("0")
    j49 = k49 * factor

    # Row 50
    g50 = g50_sum
    i50 = i50_sum
    j50 = i50
    k50 = (j50 / factor) if j50 != 0 else Decimal("0")

    # Row 51
    k51 = k48 - k49 - k50
    j51 = k51 * factor

    # Row 52
    j52 = k52 * factor

    # Row 53
    k53 = k51 - k52
    j53 = j51 - j52

    bottom3 = {
        "j46": j46, "k46": k46,
        "g47": g47, "i47": i47, "j47": j47, "k47": k47,
        "j48": j48, "k48": k48,
        "j49": j49, "k49": k49,
        "g50": g50, "i50": i50, "j50": j50, "k50": k50,
        "j51": j51, "k51": k51,
        "j52": j52, "k52": k52,
        "j53": j53, "k53": k53,
    }
    # ------------------------------------------------------------------
    # 4) Context – keep old keys AND new ones
    # ------------------------------------------------------------------
    context = {
        'interval_year': interval_year,
        'interval_start_month': interval_start,
        'window': window,

        'clients': HALFYEAR_CLIENTS_LEFT,
        'rows': rows_left,

        'clients_left': HALFYEAR_CLIENTS_LEFT,
        'rows_left': rows_left,

        'clients_right': RIGHT_CLIENTS,
        'rows_right': rows_right,
        'rows_sum': rows_sum,
        'bottom1_rows': bottom1_rows,
    }
    context["bottom2"] = bottom2
    context["bottom3"] = bottom3
    context["context_bottom2_g39"] = bottom2_inputs["g39"]
    context["context_bottom2_i39"] = bottom2_inputs["i39"]
    return context