"""Tests for canonical MITRE kill-chain ordering in coverage-by-tactic.

Block 3 fix: TacticCoverageChart.tsx (dashboard) rendered whatever order
the backend happened to return (alphabetical, and only tactics with
seeded techniques), while ExecutiveDashboardPage.tsx re-sorted client-side
into the correct kill-chain order. get_coverage_by_tactic now returns the
canonical order — and all 14 tactics, zero-filled — so both consumers get
consistent results without needing their own reordering logic.
"""

from app.models.technique import Technique
from app.services.metrics_query_service import MITRE_TACTIC_ORDER, get_coverage_by_tactic


def test_coverage_by_tactic_returns_canonical_kill_chain_order(db):
    # Seed a few tactics out of order to prove the response isn't alphabetical.
    db.add(Technique(mitre_id="T3001", name="A", tactic="impact"))
    db.add(Technique(mitre_id="T3002", name="B", tactic="execution"))
    db.add(Technique(mitre_id="T3003", name="C", tactic="reconnaissance"))
    db.commit()

    rows = get_coverage_by_tactic(db)
    tactics = [r.tactic for r in rows]

    canonical_present = [t for t in tactics if t in MITRE_TACTIC_ORDER]
    assert canonical_present == MITRE_TACTIC_ORDER


def test_coverage_by_tactic_zero_fills_tactics_with_no_techniques(db):
    db.add(Technique(mitre_id="T3004", name="D", tactic="execution"))
    db.commit()

    rows = get_coverage_by_tactic(db)
    by_tactic = {r.tactic: r for r in rows}

    assert "persistence" in by_tactic
    assert by_tactic["persistence"].total == 0
    assert by_tactic["execution"].total == 1


def test_coverage_by_tactic_unknown_tactic_sorts_last(db):
    db.add(Technique(mitre_id="T3005", name="E", tactic=None))
    db.commit()

    rows = get_coverage_by_tactic(db)
    tactics = [r.tactic for r in rows]

    assert tactics[-1] == "unknown"
