import json
import subprocess
from pathlib import Path


HANDOFF = Path(__file__).parents[1] / "frontend" / "today-handoff.js"


def run_node(script: str):
    result = subprocess.run(["node", "-e", script], capture_output=True, text=True)
    assert result.returncode == 0, result.stderr
    return json.loads(result.stdout)


def test_due_wrap_up_commitments_are_reviewed_in_order_and_added_durably():
    script = f"""
const createHandoff=require({json.dumps(str(HANDOFF))});
const values=new Map();
const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}};
const items=[
 {{kind:'issue',repository:'r',number:2,title:'Second'}},
 {{kind:'issue',repository:'r',number:1,title:'First'}},
];
const identity=item=>'issue:'+item.repository+':'+item.number+':';
const today=[]; const operations=[];
const controller=createHandoff({{
 storage,getLogin:()=> 'timmy',identity,
 todayWork:{{contains:item=>today.includes(identity(item)),add:item=>{{if(today.length>=1)return 'full';today.push(identity(item));return 'added';}}}},
 todaySync:{{enqueue:(action,id)=>{{operations.push([action,id]);return true;}},flush:async()=>true}},
}});
controller.capture(['issue:r:1:','issue:r:2:','issue:r:1:']);
const review=controller.review(items);
controller.choose('issue:r:2:',false);
const first=await controller.commit(items);
controller.choose('issue:r:2:',true);
const blocked=await controller.commit(items);
process.stdout.write(JSON.stringify({{review,first,blocked,today,operations,pending:controller.pending()}}));
"""
    result = run_node(f"(async()=>{{{script}}})().catch(error=>{{console.error(error);process.exit(1);}})")
    assert [row["identity"] for row in result["review"]] == ["issue:r:1:", "issue:r:2:"]
    assert all(row["selected"] for row in result["review"])
    assert result["first"] == {"scheduled": 1, "blocked": 0, "remaining": 1}
    assert result["blocked"] == {"scheduled": 0, "blocked": 1, "remaining": 1}
    assert result["today"] == ["issue:r:1:"]
    assert result["operations"] == [["add", "issue:r:1:"]]
    assert result["pending"] == ["issue:r:2:"]


def test_handoff_pending_state_is_account_scoped_and_capture_is_idempotent():
    script = f"""
const createHandoff=require({json.dumps(str(HANDOFF))});
const values=new Map();let login='timmy';
const storage={{getItem:k=>values.get(k)||null,setItem:(k,v)=>values.set(k,v),removeItem:k=>values.delete(k)}};
const options={{storage,getLogin:()=>login,identity:item=>item.id,todayWork:{{contains:()=>false,add:()=> 'added'}},todaySync:{{enqueue:()=>true,flush:async()=>true}}}};
const controller=createHandoff(options);
controller.capture(['one','two']);controller.capture(['two','one']);
const timmy=controller.pending();login='alexander';const isolated=controller.pending();
login='timmy';const resumed=createHandoff(options).pending();
process.stdout.write(JSON.stringify({{timmy,isolated,resumed}}));
"""
    assert run_node(f"(async()=>{{{script}}})()") == {
        "timmy": ["one", "two"], "isolated": [], "resumed": ["one", "two"],
    }


def test_dashboard_packages_accessible_mobile_commitment_review_and_account_sync():
    from src import main

    html = main.FRONTEND_BUILD.dashboard_html
    dashboard = (HANDOFF.parents[0] / "dashboard.js").read_text()
    css = (HANDOFF.parents[0] / "dashboard.css").read_text()
    service_worker = (HANDOFF.parents[0] / "service-worker.js").read_text()

    assert 'id="today-handoff-dialog"' in html
    assert 'aria-labelledby="today-handoff-title"' in html
    assert 'id="today-handoff-items"' in html
    assert 'id="confirm-today-handoff"' in html
    assert '<script src="static/today-handoff.js"></script>' in (HANDOFF.parents[0] / "index.html").read_text()
    assert "createTodayHandoff({" in dashboard
    assert "laterSync.enqueue(action, itemId, wakeAt, handoff)" in dashboard
    assert "todayHandoff.capture(handoffs)" in dashboard
    assert ".today-handoff-actions button { min-height:44px;" in css
    assert "BASE + 'static/today-handoff.js'" in service_worker
    assert "static/today-handoff.js" in main.FRONTEND_BUILD.page_sources
