from __future__ import annotations

import csv
import datetime as dt
import json
import shutil
from pathlib import Path


ROOT = Path(r"C:\BalancedTrim\analyzer")
PACKAGE_NAME = "STUDY_000K_MULTI_MODE_ADAPTIVE_ENVELOPE_20260610"
PACKAGE_DIR = ROOT / PACKAGE_NAME
ZIP_PATH = ROOT / f"{PACKAGE_NAME}.zip"

STUDY_F_OUTPUTS = Path(
    r"C:\Study\Studies\STUDY_000F_SUCCESSFUL_OPERATING_ENVELOPE_HYPOTHESIS_20260609\outputs"
)
STUDY_I_OUTPUTS = Path(
    r"C:\Study\Studies\STUDY_000I_ADAPTIVE_ENVELOPE_THEORY_20260610\outputs"
)
STUDY_J_OUTPUTS = Path(
    r"C:\Study\Studies\STUDY_000J_EMBEDDING_VS_BOUT_STRUCTURE_20260610\outputs"
)
QUESTION_LOG = Path(r"C:\Study\Program Support\DISCOVERED_PROGRAM_QUESTIONS_20260609.txt")


def ensure_dirs() -> None:
    for subdir in ["analysis", "appendices", "figures", "manifest", "manuscript", "outputs", "reports", "source_tables"]:
        (PACKAGE_DIR / subdir).mkdir(parents=True, exist_ok=True)


def read_csv(path: Path) -> list[dict[str, str]]:
    with path.open(newline="", encoding="utf-8") as handle:
        return list(csv.DictReader(handle))


def write_csv(path: Path, rows: list[dict[str, object]], fieldnames: list[str]) -> None:
    with path.open("w", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(handle, fieldnames=fieldnames)
        writer.writeheader()
        for row in rows:
            writer.writerow(row)


def round4(value: float) -> float:
    return round(value, 4)


def escape_xml(text: str) -> str:
    return (
        str(text)
        .replace("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace('"', "&quot;")
    )


def build_outputs() -> dict[str, list[dict[str, object]]]:
    boundary_rows = read_csv(STUDY_F_OUTPUTS / "study000f_boundary_expression_table.csv")
    state_rows = read_csv(STUDY_I_OUTPUTS / "study000i_state_case_table.csv")
    subgroup_rows = read_csv(STUDY_J_OUTPUTS / "study000j_subgroup_summary.csv")

    early_low = next(row for row in state_rows if row["state_label"] == "preformation_low_burden_outside_expression")
    october_high = next(row for row in state_rows if row["state_label"] == "october_high_burden_outside_cluster")
    late_low = next(row for row in state_rows if row["state_label"] == "mature_low_burden_boundary_expression")

    early_mode = {
        "mode_id": "K1",
        "mode_label": "mode_a_long_settled_low_embedding_expression",
        "calendar_anchor": early_low["calendar_date"],
        "success_state": "successful_low_burden",
        "distance_miles_norm": float(early_low["distance_miles_norm"]),
        "running_share_28d_activity_pct": float(early_low["running_share_28d_activity_pct"]),
        "treadmill_neighbors_21d": float(early_low["treadmill_neighbors_21d"]),
        "cadence_residual_pct": float(early_low["cadence_residual_pct"]),
        "stride_residual_pct": float(early_low["stride_residual_pct"]),
        "hr_residual_bpm": float(early_low["hr_residual_bpm"]),
        "mode_signature": "low_embedding_plus_long_settled_expression",
        "why_it_matters": "This is a successful low-burden state with only modest embedding support but a very long settled outside bout.",
    }
    late_mode = {
        "mode_id": "K2",
        "mode_label": "mode_b_high_embedding_boundary_expression",
        "calendar_anchor": late_low["calendar_date"],
        "success_state": "successful_low_burden",
        "distance_miles_norm": float(late_low["distance_miles_norm"]),
        "running_share_28d_activity_pct": float(late_low["running_share_28d_activity_pct"]),
        "treadmill_neighbors_21d": float(late_low["treadmill_neighbors_21d"]),
        "cadence_residual_pct": float(late_low["cadence_residual_pct"]),
        "stride_residual_pct": float(late_low["stride_residual_pct"]),
        "hr_residual_bpm": float(late_low["hr_residual_bpm"]),
        "mode_signature": "high_embedding_plus_boundary_tolerance",
        "why_it_matters": "This is a successful low-burden state with dense embedding support and only moderate bout length.",
    }
    failed_state = {
        "mode_id": "K3",
        "mode_label": "failed_short_low_support_expression",
        "calendar_anchor": october_high["calendar_date"],
        "success_state": "failed_high_burden",
        "distance_miles_norm": float(october_high["distance_miles_norm"]),
        "running_share_28d_activity_pct": float(october_high["running_share_28d_activity_pct"]),
        "treadmill_neighbors_21d": float(october_high["treadmill_neighbors_21d"]),
        "cadence_residual_pct": float(october_high["cadence_residual_pct"]),
        "stride_residual_pct": float(october_high["stride_residual_pct"]),
        "hr_residual_bpm": float(october_high["hr_residual_bpm"]),
        "mode_signature": "short_low_support_high_burden_expression",
        "why_it_matters": "This contrast state shows the cost pattern that separates the two successful low-burden modes from a failed mode.",
    }

    mode_table = [early_mode, late_mode, failed_state]

    explanatory_matrix = [
        {
            "observation_id": "K1",
            "observation_label": "two_successful_low_burden_states_have_different_support_architectures",
            "single_adaptive_envelope_explanation": "partial",
            "multi_mode_envelope_explanation": "strong",
            "preferred_construct": "multi_mode_adaptive_envelope",
            "why": "The early low-burden state and late low-burden state are both successful, but they express success through qualitatively different support signatures.",
        },
        {
            "observation_id": "K2",
            "observation_label": "mode_a_succeeds_with_modest_embedding_but_extreme_settlement",
            "single_adaptive_envelope_explanation": "partial",
            "multi_mode_envelope_explanation": "strong",
            "preferred_construct": "multi_mode_adaptive_envelope",
            "why": "A single shifting envelope can describe the difference numerically, but the long-settled low-embedding success route looks structurally distinct rather than merely weaker or stronger.",
        },
        {
            "observation_id": "K3",
            "observation_label": "mode_b_succeeds_with_dense_embedding_and_boundary_tolerance",
            "single_adaptive_envelope_explanation": "partial",
            "multi_mode_envelope_explanation": "strong",
            "preferred_construct": "multi_mode_adaptive_envelope",
            "why": "The mature boundary run remained low burden through a support architecture very different from the early long-bout success route.",
        },
        {
            "observation_id": "K4",
            "observation_label": "failed_outside_expression_clusters_around_short_low_support_runs",
            "single_adaptive_envelope_explanation": "strong",
            "multi_mode_envelope_explanation": "strong",
            "preferred_construct": "multi_mode_adaptive_envelope",
            "why": "Both models can organize the failed October state, but only the multi-mode model cleanly distinguishes two different successful alternatives rather than one success band.",
        },
        {
            "observation_id": "K5",
            "observation_label": "000J_state_conditional_support_architecture_puts_pressure_on_a_single_success_route",
            "single_adaptive_envelope_explanation": "weak_to_partial",
            "multi_mode_envelope_explanation": "strong",
            "preferred_construct": "multi_mode_adaptive_envelope",
            "why": "Once support architecture itself varies by state, one generic route to low-burden success becomes harder to defend.",
        },
    ]

    theory_tests = [
        {
            "test_label": "two_successful_low_burden_configurations_exist",
            "result": "supported",
            "interpretation": "The archive contains an early low-embedding long-settled low-burden state and a later high-embedding boundary low-burden state.",
        },
        {
            "test_label": "successful_low_burden_expression_is_not_limited_to_one_support_architecture",
            "result": "supported",
            "interpretation": "Low-burden outside expression was achieved through more than one support signature, which pressures a single-route explanation.",
        },
        {
            "test_label": "multi_mode_logic_organizes_000F_000I_000J_better_than_one_success_route",
            "result": "supported",
            "interpretation": "The archive is better explained by at least two candidate successful modes than by one singular successful architecture that only changes strength.",
        },
    ]

    evidence_matrix = [
        {
            "family_id": "K1",
            "family_label": "mode_a_signature",
            "observation": "An early low-burden outside run succeeded with modest embedding and extreme bout settlement.",
            "key_values": f"distance {round4(early_mode['distance_miles_norm'])}, running share {round4(early_mode['running_share_28d_activity_pct'])}%, neighbors {round4(early_mode['treadmill_neighbors_21d'])}, burden {round4(early_mode['hr_residual_bpm'])} bpm",
            "support_strength": "strong",
        },
        {
            "family_id": "K2",
            "family_label": "mode_b_signature",
            "observation": "A later low-burden boundary run succeeded with dense embedding and moderate bout length.",
            "key_values": f"distance {round4(late_mode['distance_miles_norm'])}, running share {round4(late_mode['running_share_28d_activity_pct'])}%, neighbors {round4(late_mode['treadmill_neighbors_21d'])}, burden {round4(late_mode['hr_residual_bpm'])} bpm",
            "support_strength": "strong",
        },
        {
            "family_id": "K3",
            "family_label": "failed_contrast_state",
            "observation": "The October cluster remained high burden under short, low-support conditions and separates the two successful states from a failed route.",
            "key_values": f"distance {round4(failed_state['distance_miles_norm'])}, running share {round4(failed_state['running_share_28d_activity_pct'])}%, neighbors {round4(failed_state['treadmill_neighbors_21d'])}, burden {round4(failed_state['hr_residual_bpm'])} bpm",
            "support_strength": "strong",
        },
        {
            "family_id": "K4",
            "family_label": "000J_pressure_on_single_hierarchy",
            "observation": "State-conditional support architecture means the same protective ranking did not hold unchanged across states.",
            "key_values": "000J: bout structure led in the direct divergence case, while embedding remained strong in the later specialized state.",
            "support_strength": "strong",
        },
    ]

    mode_comparison = [
        {
            "comparison_axis": "success_mode",
            "mode_a_long_settled_low_embedding_expression": "present",
            "mode_b_high_embedding_boundary_expression": "present",
            "failed_short_low_support_expression": "absent",
        },
        {
            "comparison_axis": "embedding_support",
            "mode_a_long_settled_low_embedding_expression": "low_to_moderate",
            "mode_b_high_embedding_boundary_expression": "very_high",
            "failed_short_low_support_expression": "low",
        },
        {
            "comparison_axis": "bout_structure",
            "mode_a_long_settled_low_embedding_expression": "very_long_settled",
            "mode_b_high_embedding_boundary_expression": "moderate_boundary",
            "failed_short_low_support_expression": "short_probe_cluster",
        },
        {
            "comparison_axis": "burden_outcome",
            "mode_a_long_settled_low_embedding_expression": "low_burden",
            "mode_b_high_embedding_boundary_expression": "low_burden",
            "failed_short_low_support_expression": "high_burden",
        },
    ]

    scope_claims = [
        {
            "claim_type": "supported",
            "claim": "The archive supports at least two candidate successful low-burden envelope modes rather than one single success route.",
        },
        {
            "claim_type": "supported",
            "claim": "The early long-settled low-embedding state and the later high-embedding boundary state are qualitatively different successful configurations.",
        },
        {
            "claim_type": "not_supported",
            "claim": "Every possible successful envelope mode has already been observed and mapped.",
        },
        {
            "claim_type": "not_supported",
            "claim": "The archive can already prospectively predict which mode will be active before a run.",
        },
    ]

    primary_answer = [
        {
            "question_id": "Q026",
            "study_id": "000K",
            "core_question": "Are there multiple successful envelope modes rather than one envelope that simply shifts across state and phase?",
            "answer": "yes_supported",
            "answer_plain": "Yes. The archive is better explained by at least two candidate successful low-burden envelope modes than by a single success route that only changes strength.",
        }
    ]

    discovered_questions = [
        {
            "question_id": "Q026",
            "status": "ADDRESSED",
            "answered_in": "Study 000K",
            "question": "Are there multiple successful envelope modes rather than one envelope that simply shifts across state and phase?",
        },
        {
            "question_id": "Q028",
            "status": "OPEN",
            "answered_in": "",
            "question": "What determines which successful envelope mode becomes available or preferred at a given point in adaptation?",
        },
    ]

    return {
        "study000k_primary_answer": primary_answer,
        "study000k_mode_table": mode_table,
        "study000k_explanatory_matrix": explanatory_matrix,
        "study000k_theory_tests": theory_tests,
        "study000k_evidence_family_matrix": evidence_matrix,
        "study000k_mode_comparison": mode_comparison,
        "study000k_scope_claims": scope_claims,
        "study000k_discovered_questions": discovered_questions,
    }


def write_outputs(outputs: dict[str, list[dict[str, object]]]) -> None:
    out_dir = PACKAGE_DIR / "outputs"
    for stem, rows in outputs.items():
        write_csv(out_dir / f"{stem}.csv", rows, list(rows[0].keys()) if rows else [])


def build_figures(outputs: dict[str, list[dict[str, object]]]) -> None:
    fig_dir = PACKAGE_DIR / "figures"
    mode_rows = outputs["study000k_mode_table"]

    width = 980
    height = 420
    left = 90
    right = 40
    top = 50
    bottom = 320
    plot_w = width - left - right
    plot_h = bottom - top
    max_x = max(float(row["distance_miles_norm"]) for row in mode_rows) + 1.0
    max_y = max(float(row["running_share_28d_activity_pct"]) for row in mode_rows) + 5.0

    def color(state: str) -> str:
        return "#2a9d8f" if state == "successful_low_burden" else "#d62828"

    svg = [
        f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}" viewBox="0 0 {width} {height}">',
        '<rect width="100%" height="100%" fill="#fbfaf6"/>',
        '<text x="28" y="28" font-size="18" font-family="Georgia" fill="#222">Candidate Successful Envelope Modes</text>',
    ]
    for row in mode_rows:
        x = left + (float(row["distance_miles_norm"]) / max_x) * plot_w
        y = bottom - (float(row["running_share_28d_activity_pct"]) / max_y) * plot_h
        svg.append(f'<circle cx="{x:.2f}" cy="{y:.2f}" r="9" fill="{color(row["success_state"])}"/>')
        svg.append(f'<text x="{x+10:.2f}" y="{y-5:.2f}" font-size="10" font-family="Arial">{escape_xml(row["mode_label"])}</text>')
    svg.append('<text x="30" y="355" font-size="11" font-family="Arial">Green = successful low-burden mode, red = failed high-burden contrast state</text>')
    svg.append('</svg>')
    (fig_dir / "figure01_mode_space_scatter.svg").write_text("\n".join(svg), encoding="utf-8")

    width = 960
    height = 320
    x_positions = [120, 430, 740]
    svg = [
        f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}" viewBox="0 0 {width} {height}">',
        '<rect width="100%" height="100%" fill="#fffdf8"/>',
        '<text x="28" y="28" font-size="18" font-family="Georgia" fill="#222">Mode Signatures Compared</text>',
    ]
    for x, row in zip(x_positions, mode_rows):
        svg.append(f'<rect x="{x-70}" y="70" width="180" height="170" fill="#f3f1ea" rx="8"/>')
        svg.append(f'<text x="{x}" y="95" font-size="11" font-family="Arial" text-anchor="middle">{escape_xml(row["mode_label"])}</text>')
        svg.append(f'<text x="{x}" y="125" font-size="11" font-family="Arial" text-anchor="middle">distance {round4(float(row["distance_miles_norm"]))} mi</text>')
        svg.append(f'<text x="{x}" y="150" font-size="11" font-family="Arial" text-anchor="middle">share {round4(float(row["running_share_28d_activity_pct"]))}%</text>')
        svg.append(f'<text x="{x}" y="175" font-size="11" font-family="Arial" text-anchor="middle">neighbors {round4(float(row["treadmill_neighbors_21d"]))}</text>')
        svg.append(f'<text x="{x}" y="200" font-size="11" font-family="Arial" text-anchor="middle">burden {round4(float(row["hr_residual_bpm"]))} bpm</text>')
        svg.append(f'<text x="{x}" y="225" font-size="11" font-family="Arial" text-anchor="middle">{escape_xml(row["mode_signature"])}</text>')
    svg.append("</svg>")
    (fig_dir / "figure02_mode_signature_cards.svg").write_text("\n".join(svg), encoding="utf-8")

    width = 960
    height = 280
    svg = [
        f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}" viewBox="0 0 {width} {height}">',
        '<rect width="100%" height="100%" fill="#fbfcff"/>',
        '<text x="28" y="28" font-size="18" font-family="Georgia" fill="#222">From One Envelope To Multiple Successful Modes</text>',
        '<text x="80" y="90" font-size="14" font-family="Arial">Operating Envelope</text>',
        '<text x="80" y="120" font-size="14" font-family="Arial">Adaptive Envelope</text>',
        '<text x="80" y="150" font-size="14" font-family="Arial">State-Conditional Support Architecture</text>',
        '<text x="80" y="180" font-size="14" font-family="Arial">Multiple Successful Modes</text>',
        '<line x1="280" y1="88" x2="410" y2="88" stroke="#222" stroke-width="2"/>',
        '<line x1="280" y1="118" x2="410" y2="118" stroke="#222" stroke-width="2"/>',
        '<line x1="280" y1="148" x2="410" y2="148" stroke="#222" stroke-width="2"/>',
        '<line x1="280" y1="178" x2="410" y2="178" stroke="#222" stroke-width="2"/>',
        '<text x="450" y="90" font-size="13" font-family="Arial">000F</text>',
        '<text x="450" y="120" font-size="13" font-family="Arial">000I</text>',
        '<text x="450" y="150" font-size="13" font-family="Arial">000J</text>',
        '<text x="450" y="180" font-size="13" font-family="Arial">000K</text>',
        '</svg>',
    ]
    (fig_dir / "figure03_theory_progression.svg").write_text("\n".join(svg), encoding="utf-8")


def build_reports(outputs: dict[str, list[dict[str, object]]]) -> None:
    reports_dir = PACKAGE_DIR / "reports"
    mode_rows = outputs["study000k_mode_table"]
    mode_a = mode_rows[0]
    mode_b = mode_rows[1]
    failed = mode_rows[2]

    results_text = f"""# Study 000K Results

## Primary Answer

`Yes, supported.`

The archive is better explained by at least `two candidate successful low-burden envelope modes` than by one single success route that only changes strength across state and phase.

## Candidate Successful Modes

- Mode A: `long-settled low-embedding expression`
  - anchor: `{mode_a["calendar_anchor"]}`
  - distance: `{round4(float(mode_a["distance_miles_norm"]))} miles`
  - running-share context: `{round4(float(mode_a["running_share_28d_activity_pct"]))}%`
  - treadmill neighbors: `{round4(float(mode_a["treadmill_neighbors_21d"]))}`
  - HR residual burden: `{round4(float(mode_a["hr_residual_bpm"]))} bpm`

- Mode B: `high-embedding boundary expression`
  - anchor: `{mode_b["calendar_anchor"]}`
  - distance: `{round4(float(mode_b["distance_miles_norm"]))} miles`
  - running-share context: `{round4(float(mode_b["running_share_28d_activity_pct"]))}%`
  - treadmill neighbors: `{round4(float(mode_b["treadmill_neighbors_21d"]))}`
  - HR residual burden: `{round4(float(mode_b["hr_residual_bpm"]))} bpm`

## Failed Contrast State

- failed short low-support expression:
  - anchor: `{failed["calendar_anchor"]}`
  - distance: `{round4(float(failed["distance_miles_norm"]))} miles`
  - running-share context: `{round4(float(failed["running_share_28d_activity_pct"]))}%`
  - treadmill neighbors: `{round4(float(failed["treadmill_neighbors_21d"]))}`
  - HR residual burden: `{round4(float(failed["hr_residual_bpm"]))} bpm`

## Interpretation

The central theory advance is not just that the envelope adapts.

It is that the archive now supports more than one `successful low-burden route`:

- one route that tolerates low embedding through very long settled expression
- another route that tolerates outside-surface expression through dense embedding support

That is stronger than a single-envelope-strength story.
It is a candidate `multi-mode adaptive-envelope` story.
"""
    (reports_dir / "STUDY000K_RESULTS.md").write_text(results_text, encoding="utf-8")

    methods_text = """# Study 000K Methods

Study `000K` is a flagship theory test built from:

- `000F` operating-envelope evidence
- `000I` adaptive-envelope state logic
- `000J` state-conditional support architecture

The theory question was:

`Are there multiple successful envelope modes rather than one envelope that simply shifts across state and phase?`

The core test was explanatory:

1. identify the successful low-burden outside-expression states already present in the archive
2. compare whether those states represent one route with different strength, or genuinely different successful support configurations
3. compare both against the failed October high-burden state
"""
    (reports_dir / "STUDY000K_METHODS.md").write_text(methods_text, encoding="utf-8")

    discussion_text = """# Study 000K Discussion

`000K` is the first study in the archive that explicitly challenges the singularity of the envelope model.

After `000I`, the archive could still be read as:

`one adaptive envelope whose support requirements change over time`

After `000J`, that became harder to defend because the support architecture itself stopped behaving like one stable hierarchy.

`000K` pushes the theory one step further:

`the archive is better explained by at least two successful low-burden modes`

This does not mean every future mode is already known.
It means the archive has now crossed the threshold where one single success architecture is no longer the cleanest explanation.
"""
    (reports_dir / "STUDY000K_DISCUSSION.md").write_text(discussion_text, encoding="utf-8")

    audit_text = """# Study 000K Audit

## Structural Audit

This package is structurally sound.

It includes:

- candidate mode table
- explanatory matrix
- theory tests
- figures
- manuscript and report set
- build script

## Scientific Audit

Study `000K` asks:

`Are there multiple successful envelope modes rather than one envelope that simply shifts across state and phase?`

The answer is:

`Yes, supported.`

Why:

- the archive contains at least two successful low-burden states with qualitatively different support architectures
- `000J` showed those support architectures do not behave like one fixed hierarchy
- the failed October state helps separate successful modes from unsuccessful outside-context expression

## Boundaries

- This study supports at least two candidate successful modes, not a complete mode atlas.
- It does not yet identify how the system chooses one successful mode over another.
- It does not yet make the model prospectively predictive.
"""
    (reports_dir / "STUDY000K_AUDIT.md").write_text(audit_text, encoding="utf-8")

    plain_text = """# Study 000K Plain-Language Summary

Study `000K` asks whether the archive is describing one successful running mode that shifts over time, or more than one successful low-burden mode.

The stronger answer is:

`more than one successful mode`

The dataset now contains:

- an early low-burden outside run that succeeded with only modest embedding but a very long settled bout
- a later low-burden outside run that succeeded with dense embedding support and only moderate bout length

Those look like different successful routes, not just one route that became stronger or weaker.
"""
    (reports_dir / "STUDY000K_PLAIN_LANGUAGE_SUMMARY.md").write_text(plain_text, encoding="utf-8")

    manuscript_text = """# Study 000K: Multi-Mode Adaptive Envelope

## Core Question

Are there multiple successful envelope modes rather than one envelope that simply shifts across state and phase?

## Answer

Yes, supported.

## Thesis

`The archive is better explained by at least two candidate successful low-burden envelope modes than by one single success route whose support requirements merely change strength over time.`
"""
    (PACKAGE_DIR / "manuscript" / "STUDY000K_MANUSCRIPT.md").write_text(manuscript_text, encoding="utf-8")


def copy_sources() -> None:
    source_dir = PACKAGE_DIR / "source_tables"
    for path in [
        STUDY_F_OUTPUTS / "study000f_boundary_expression_table.csv",
        STUDY_I_OUTPUTS / "study000i_state_case_table.csv",
        STUDY_J_OUTPUTS / "study000j_subgroup_summary.csv",
        STUDY_J_OUTPUTS / "study000j_factor_comparison_matrix.csv",
    ]:
        shutil.copy2(path, source_dir / path.name)


def build_readme() -> None:
    (PACKAGE_DIR / "README.md").write_text(
        "# STUDY_000K_MULTI_MODE_ADAPTIVE_ENVELOPE_20260610\n\n"
        "Flagship theory study testing whether the archive is better explained by multiple successful low-burden envelope modes rather than one success route that only shifts strength.\n",
        encoding="utf-8",
    )


def build_manifest(outputs: dict[str, list[dict[str, object]]]) -> None:
    manifest = {
        "package_name": PACKAGE_NAME,
        "generated_at": dt.datetime.now(dt.timezone.utc).isoformat(),
        "primary_answer": outputs["study000k_primary_answer"][0]["answer_plain"],
        "candidate_modes": 2,
        "contrast_states": 1,
    }
    (PACKAGE_DIR / "manifest" / "study000k_state.json").write_text(json.dumps(manifest, indent=2), encoding="utf-8")


def update_question_log() -> None:
    if not QUESTION_LOG.exists():
        return
    text = QUESTION_LOG.read_text(encoding="utf-8")
    qid = "Q026"
    marker = f"{qid}\n"
    idx = text.find(marker)
    if idx != -1:
        next_idx = text.find("\n\nQ", idx + 1)
        if next_idx == -1:
            next_idx = len(text)
        block = text[idx:next_idx]
        lines = block.splitlines()
        new_lines = []
        inserted_answered = False
        inserted_answer = False
        for line in lines:
            if line.startswith("Status:"):
                new_lines.append("Status: ADDRESSED")
            elif line.startswith("Answered In:"):
                inserted_answered = True
                new_lines.append("Answered In:")
                new_lines.append("Study 000K")
            elif line.startswith("Answer:"):
                inserted_answer = True
                new_lines.append("Answer:")
                new_lines.append("Yes. The archive is better explained by at least two candidate successful low-burden envelope modes than by one single success route.")
            else:
                new_lines.append(line)
        if not inserted_answered:
            new_lines.extend(["Answered In:", "Study 000K"])
        if not inserted_answer:
            new_lines.extend(["Answer:", "Yes. The archive is better explained by at least two candidate successful low-burden envelope modes than by one single success route."])
        text = text[:idx] + "\n".join(new_lines) + text[next_idx:]
    if "Q028" not in text:
        text = text.rstrip() + (
            "\n\nQ028\n"
            "Status: OPEN\n"
            "Born From: Study 000K\n"
            "Question:\n"
            "What determines which successful envelope mode becomes available or preferred at a given point in adaptation?\n"
            "Why It Matters:\n"
            "If answered, the archive could move from identifying multiple successful modes to explaining mode selection itself.\n"
            "Notes:\n"
            "Study 000K supported at least two candidate successful low-burden modes, but did not yet identify how the system enters one mode versus another.\n"
        )
    QUESTION_LOG.write_text(text, encoding="utf-8")


def copy_builder() -> None:
    shutil.copy2(Path(__file__), PACKAGE_DIR / "analysis" / Path(__file__).name)


def build_zip() -> None:
    if ZIP_PATH.exists():
        ZIP_PATH.unlink()
    shutil.make_archive(str(PACKAGE_DIR), "zip", root_dir=PACKAGE_DIR)


def main() -> None:
    if PACKAGE_DIR.exists():
        shutil.rmtree(PACKAGE_DIR)
    ensure_dirs()
    outputs = build_outputs()
    write_outputs(outputs)
    build_figures(outputs)
    build_reports(outputs)
    copy_sources()
    build_readme()
    build_manifest(outputs)
    update_question_log()
    copy_builder()
    build_zip()
    print(PACKAGE_DIR)
    print(ZIP_PATH)


if __name__ == "__main__":
    main()
