import json
import subprocess
from pathlib import Path

import pytest

from tests.dashboard_bundle import dashboard


READINESS = Path(__file__).parents[1] / "frontend" / "plan-today-readiness.js"


def run_node(script: str) -> dict:
    result = subprocess.run(["node", "-e", script], check=True, capture_output=True, text=True)
    return json.loads(result.stdout)


def test_plan_readiness_bounds_concurrency_and_preserves_ranked_order():
    script = f"""
const createReadiness = require({json.dumps(str(READINESS))});
let active = 0;
let peak = 0;
const completed = [];
const delays = {{1:40, 2:5, 3:20, 4:1, 5:10, 6:2}};
const readiness = createReadiness({{
  concurrency:3,
  identity:item => 'issue:' + item.number,
  inspect:async item => {{
    active += 1;
    peak = Math.max(peak, active);
    await new Promise(resolve => setTimeout(resolve, delays[item.number]));
    completed.push(item.number);
    active -= 1;
    return item.number === 4 ? {{status:'blocked', reason:'Waiting'}} : {{status:'ready'}};
  }},
}});
readiness.run([1,2,3,4,5,6].map(number => ({{kind:'issue', number}}))).then(result => {{
  process.stdout.write(JSON.stringify({{peak, completed, entries:Object.entries(result)}}));
}});
"""
    result = run_node(script)
    assert result["peak"] == 3
    assert result["completed"] != [1, 2, 3, 4, 5, 6]
    assert result["entries"] == [
        ["issue:1", {"status": "ready"}],
        ["issue:2", {"status": "ready"}],
        ["issue:3", {"status": "ready"}],
        ["issue:4", {"status": "blocked", "reason": "Waiting"}],
        ["issue:5", {"status": "ready"}],
        ["issue:6", {"status": "ready"}],
    ]


def test_plan_readiness_supersedes_stale_builds_and_normalizes_real_failures():
    script = f"""
const createReadiness = require({json.dumps(str(READINESS))});
let releaseFirst;
const firstGate = new Promise(resolve => {{ releaseFirst = resolve; }});
const readiness = createReadiness({{
  concurrency:2,
  identity:item => 'issue:' + item.number,
  inspect:async item => {{
    if (item.number === 1) await firstGate;
    if (item.number === 3) throw new Error('upstream details');
    return {{status:'ready'}};
  }},
}});
const stale = readiness.run([{{number:1}}, {{number:2}}]);
const current = readiness.run([{{number:3}}, {{number:4}}]);
current.then(currentResult => {{
  releaseFirst();
  stale.then(staleResult => process.stdout.write(JSON.stringify({{staleResult, currentResult}})));
}});
"""
    assert run_node(script) == {
        "staleResult": None,
        "currentResult": {
            "issue:3": {"status": "unverified"},
            "issue:4": {"status": "ready"},
        },
    }


@pytest.mark.anyio
async def test_dashboard_uses_bounded_supersedable_readiness_for_build_my_today():
    html = await dashboard()

    assert '<script src="static/plan-today-readiness.js"></script>' in html
    assert "const planTodayReadiness = createPlanTodayReadiness({" in html
    assert "concurrency:3" in html
    assert "const checks = await planTodayReadiness.run(candidates);" in html
    assert "if (!checks) return;" in html
    assert "planTodayReadiness.cancel();" in html
    assert "Promise.all(candidates.map" not in html
