const assert=require('assert');
const fs=require('fs');
const vm=require('vm');

const source=fs.readFileSync('static/app.js','utf8');
const start=source.indexOf("function cpath(");
const end=source.indexOf("async function runCharacterAutofill",start);
assert(start>=0&&end>start,'autofill client functions not found');

const elements={};
const context={
  console,
  state:{},
  Event:class Event{constructor(type,options){this.type=type;this.options=options}},
  $:selector=>elements[selector.replace(/^#/,'')]||null,
  escapeHtml:String,
};
vm.createContext(context);
vm.runInContext(source.slice(start,end),context);

const mapText=source.slice(source.indexOf('const map={',start),end);
const pairs=[...mapText.matchAll(/'([^']+)':'([^']+)'/g)].map(([,path,id])=>[path,id]);
assert(pairs.length>=100,`expected full dossier map, got ${pairs.length}`);
for(const [,id] of pairs)elements[id]={value:'',dispatchEvent(){}};
elements.characterAutofillStatus={innerHTML:''};

const flatFields={};
for(const [path] of pairs)flatFields[path]=path==='public_description'?'Summary only':path.endsWith('.traits')?['focused','loyal']:`value:${path}`;
context.applyCharacterAutofill({fields:flatFields,sources:[{url:'https://example.test'}]},false);
for(const [path,id] of pairs)assert(elements[id].value,`${path} was dropped by flat-key mapping`);
assert.strictEqual(elements.creatorSummary.value,'Summary only');

for(const [,id] of pairs)elements[id].value='';
const aliasedFields={
  description:'Alias summary',
  appearance_profile:{height:'170 cm',eye_color:'green',hair_color:'black'},
  personality:{traits:['patient'],strengths:['brave']},
  life_history:{background:'Raised abroad'},
  relationships:{family:['A — parent']},
  preferences:{likes:['tea']},
  rp_behavior:{speech_style:'formal'},
  knowledge_skills:{talents:['music']},
  lore:{species:'human'},
  continuity:{immutable_facts:['Never lies']},
};
assert.strictEqual(context.characterAutofillValue(aliasedFields,'appearance.height',''),'170 cm');
context.applyCharacterAutofill({fields:aliasedFields},false);
assert.strictEqual(elements.charHeight.value,'170 cm');
assert.strictEqual(elements.charEyeColor.value,'green');
assert.strictEqual(elements.charHairColor.value,'black');
assert.strictEqual(elements.charPersonality.value,'patient');
assert.strictEqual(elements.charBackground.value,'Raised abroad');
assert.strictEqual(elements.charFamily.value,'A — parent');
assert.strictEqual(elements.charLikes.value,'tea');
assert.strictEqual(elements.charSpeech.value,'formal');
assert.strictEqual(elements.charTalents.value,'music');
assert.strictEqual(elements.charSpecies.value,'human');
assert.strictEqual(elements.charImmutable.value,'Never lies');
assert.strictEqual(elements.creatorSummary.value,'Alias summary');

elements.charHeight.value='User-authored height';
context.applyCharacterAutofill({fields:{appearance:{height:'190 cm'}}},false);
assert.strictEqual(elements.charHeight.value,'User-authored height','non-Replace overwrote user content');
context.applyCharacterAutofill({fields:{appearance:{height:'190 cm'}}},true);
assert.strictEqual(elements.charHeight.value,'190 cm','Replace did not overwrite user content');

console.log(`character autofill contract: ${pairs.length} mapped fields passed`);
