"""Scoring, parsing, and assembly — the glue the notebook leans on."""

from datetime import date

import pytest

from diaglib import (
    build_engagement,
    build_scores,
    dimension_rollup,
    evidence_coverage,
    heatmap_grid,
    make_engagement_id,
    parse_participants,
    value_at_stake,
)
from tests.conftest import SCORED_AT, SEED_SCORES

approx = pytest.approx


def test_engagement_id_slug():
    assert make_engagement_id("Acme", date(2026, 7, 19)) == "acme_2026-07-19"
    assert make_engagement_id("  Acme & Söhne GmbH! ",
                              date(2026, 7, 19)) == "acme_s_hne_gmbh_2026-07-19"
    assert make_engagement_id("", date(2026, 7, 19)) == "client_2026-07-19"


def test_parse_participants_forgiving():
    got = parse_participants(
        "Jane Example | VP Customer Experience | cx; "
        "Raj Patel|CIO|IT; Sam Sample | Ops Director; Solo")
    assert [(p.name, p.role, p.function) for p in got] == [
        ("Jane Example", "VP Customer Experience", "cx"),
        ("Raj Patel", "CIO", "it"),                  # case-normalized
        ("Sam Sample", "Ops Director", "other"),     # function missing
        ("Solo", "", "other"),
    ]
    assert parse_participants("") == []
    assert parse_participants(" ; ; ") == []


def test_build_scores_orders_and_validates(config):
    scores = build_scores(config, SEED_SCORES, scored_at=SCORED_AT)
    assert [s.competency_id for s in scores] == [c.id for c in config.competencies]
    assert all(s.scored_at == SCORED_AT for s in scores)
    with pytest.raises(ValueError, match="unscored"):
        build_scores(config, {"data_readiness": (3, "")}, scored_at=SCORED_AT)


def test_dimension_rollup_pins(config, scores):
    rollup = {dim_id: mean for dim_id, _, mean in dimension_rollup(config, scores)}
    assert rollup["strategy_value"] == approx((2 + 2 + 3) / 3)
    assert rollup["foundations"] == approx((3 + 2 + 3) / 3)
    assert rollup["delivery"] == approx((3 + 3 + 2) / 3)
    assert rollup["sustain"] == approx((2 + 3 + 3) / 3)


def test_evidence_coverage(config, scores):
    assert evidence_coverage(scores) == (12, 12)   # fixture captures all evidence
    blank = [s.model_copy(update={"evidence": ""}) for s in scores[:3]] + scores[3:]
    assert evidence_coverage(blank) == (9, 12)


def test_heatmap_grid_shape(config, scores):
    grid = heatmap_grid(config, scores)
    assert grid["rows"] == ["Strategy & Value", "Foundations", "Delivery", "Sustain"]
    assert [len(r) for r in grid["z"]] == [3, 3, 3, 3]
    assert grid["z"][1] == [3, 2, 3]        # foundations row: pd, dr, ta
    assert "Data Readiness" in grid["text"][1][1]
    assert "KB stale" in grid["hover"][1][1]     # evidence surfaces on hover


def test_build_engagement_assembles(config, baseline, scores):
    vas = value_at_stake(config, baseline, scores)
    eng = build_engagement(
        config=config, client_name="Acme Demo Co", facilitator="Robert Helewka",
        workshop_date=date(2026, 7, 19),
        participants=parse_participants("Jane Example | VP CX | cx"),
        baseline=baseline, scores=scores, computed_value=vas,
        notes="dry run")
    assert eng.engagement_id == "acme_demo_co_2026-07-19"
    assert eng.industry_config == "contact_center"
    assert len(eng.scores) == 12
    assert eng.computed_value.binding_constraints == ["data_readiness"]
