import json
import subprocess
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
STORE = ROOT / "frontend" / "search-reply-draft-store.js"
ATTACHMENT = ROOT / "frontend" / "issue-attachment.js"
INDEX = ROOT / "frontend" / "index.html"
DASHBOARD = ROOT / "frontend" / "dashboard.js"
REGISTRY = ROOT / "frontend" / "private-data-registry.js"
WORKER = ROOT / "frontend" / "service-worker.js"


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


def test_search_reply_photo_drafts_restore_only_for_the_confirmed_account_and_exact_result():
    script = f"""
const createStore = require({json.dumps(str(STORE))});
const records = new Map();
let login = 'timmy';
const transaction = async (operation, key, value) => {{
  if (operation === 'put') records.set(key, structuredClone(value));
  if (operation === 'get') return records.has(key) ? structuredClone(records.get(key)) : null;
  if (operation === 'delete') records.delete(key);
}};
const store = createStore({{transaction, getOwnerLogin:()=>login}});
const target = {{kind:'issue', repository:'stackchain/dashboard', number:957}};
const other = {{kind:'issue', repository:'stackchain/dashboard', number:958}};
const photo = new Blob(['field-evidence'], {{type:'image/webp'}});
(async()=>{{
  await store.save(target, [{{
    filename:'camera.webp', contentType:'image/webp', blob:photo,
    note:'rack label', operationId:'upload-stable-1',
    confirmed:{{markdown:'![camera](confirmed-url)'}},
  }}]);
  const restored = await store.load(target);
  const wrongTarget = await store.load(other);
  login = 'alexander';
  const wrongAccount = await store.load(target);
  process.stdout.write(JSON.stringify({{
    restored:{{...restored[0], blobText:await restored[0].blob.text(), blob:undefined}},
    wrongTarget, wrongAccount, recordCount:records.size,
  }}));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
    output = json.loads(run_node(script))

    assert output == {
        "restored": {
            "filename": "camera.webp",
            "contentType": "image/webp",
            "note": "rack label",
            "operationId": "upload-stable-1",
            "confirmed": {"markdown": "![camera](confirmed-url)"},
            "blobText": "field-evidence",
        },
        "wrongTarget": None,
        "wrongAccount": None,
        "recordCount": 1,
    }


def test_photo_bundle_checkpoint_restores_stable_uploads_without_repeating_them():
    script = f"""
const attachment = require({json.dumps(str(ATTACHMENT))});
const photo = new Blob(['proof'], {{type:'image/png'}}); photo.name = 'proof.png';
const uploads = [];
const first = attachment.create({{
  createOperationId:()=> 'stable-upload-957',
  upload:async payload=>{{uploads.push(payload.operation_id);return {{markdown:'![proof](saved-url)'}};}},
}});
first.select(photo);
(async()=>{{
  await first.prepareComment({{repository:'stackchain/dashboard',number:957}}, 'Ready');
  const checkpoint = await first.serialize();
  const restored = attachment.create({{
    createOperationId:()=> 'must-not-replace-operation',
    upload:async payload=>{{uploads.push(payload.operation_id);throw new Error('must not upload twice');}},
  }});
  restored.restore(checkpoint);
  const comment = await restored.prepareComment({{repository:'stackchain/dashboard',number:957}}, 'Ready');
  process.stdout.write(JSON.stringify({{checkpoint:{{...checkpoint,blob:undefined}},comment,uploads}}));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
    output = json.loads(run_node(script))

    assert output == {
        "checkpoint": {
            "filename": "proof.png",
            "contentType": "image/png",
            "operationId": "stable-upload-957",
            "confirmed": {"markdown": "![proof](saved-url)"},
        },
        "comment": "Ready\n\n![proof](saved-url)",
        "uploads": ["stable-upload-957"],
    }


def test_dashboard_checkpoints_restores_and_clears_search_photo_drafts_at_user_boundaries():
    html = INDEX.read_text()
    dashboard = DASHBOARD.read_text()
    registry = REGISTRY.read_text()
    worker = WORKER.read_text()

    assert '<script src="static/search-reply-draft-store.js"></script>' in html
    assert html.index('static/search-reply-draft-store.js') < html.index('static/dashboard.js')
    assert "'stackchain-search-reply-drafts-v1'" in registry
    assert "BASE + 'static/search-reply-draft-store.js'" in worker
    assert "createSearchReplyDraftStore({" in dashboard
    assert "getOwnerLogin:() => confirmedOwnerLogin" in dashboard
    assert "onCheckpoint:() => persistSearchReplyPhotos()" in dashboard
    assert "searchReplyDraftStore.load(target)" in dashboard
    assert "searchReplyDraftStore.remove(item)" in dashboard
