import {PGlite} from '@electric-sql/pglite';
export const expandSQL=`ALTER TABLE profiles ADD COLUMN display_name text;
UPDATE profiles SET display_name=full_name WHERE display_name IS NULL;
-- During the compatibility window, writers must maintain BOTH columns.
UPDATE profiles SET full_name=$1,display_name=$1 WHERE id=$2;`;
export function mayContract({oldReaders,oldWriters,backfillRemaining}){return oldReaders===0&&oldWriters===0&&backfillRemaining===0;}
export async function runRollout(config,options={}){
 if(!['rename','health','contract'].includes(config.preset))throw new Error('Choose a listed release scenario.');
 const safe=config.variant==='safe',db=new PGlite(options),checks=[],trace=[];let failed=0;
 try{
  await db.exec("CREATE TABLE profiles(id int PRIMARY KEY,full_name text NOT NULL);INSERT INTO profiles VALUES(1,'Mira Chen');");
  async function probe(stage,client,query){try{const r=await db.query(query);checks.push([stage,client,'200',JSON.stringify(r.rows)]);}catch(e){failed++;checks.push([stage,client,'500',e.message]);}}
  await probe('Before release','Version 1','SELECT full_name FROM profiles WHERE id=1');
  if(!safe){
   await db.exec('ALTER TABLE profiles RENAME COLUMN full_name TO display_name');trace.push('A destructive rename removes the field that the old application still reads.');
  }else{
   await db.exec('ALTER TABLE profiles ADD COLUMN display_name text');await db.exec('UPDATE profiles SET display_name=full_name WHERE display_name IS NULL');
   await db.query('UPDATE profiles SET full_name=$1,display_name=$1 WHERE id=$2',['Mira Chen (updated)',1]);trace.push('Expand the schema, backfill existing rows, then maintain both fields during mixed-version traffic.');
  }
  await probe('Mixed versions','Version 1','SELECT full_name FROM profiles WHERE id=1');
  await probe('Mixed versions','Version 2','SELECT display_name FROM profiles WHERE id=1');
  if(config.preset==='health'){
   checks.push(['Canary readiness','Version 2','503','Injected failure: this version is not ready']);
   trace.push(safe?'The modeled controller keeps traffic on version 1 and rolls the application back. The expanded schema remains compatible.':'The modeled controller sent traffic before readiness; application rollback restores version 1 but cannot restore its deleted column.');
   await probe('Rollback','Version 1','SELECT full_name FROM profiles WHERE id=1');
  }else if(config.preset==='contract'){
   const state={oldReaders:1,oldWriters:0,backfillRemaining:0};
   if(safe&&!mayContract(state))trace.push('Contract gate refused: one old reader remains. Keep both columns and retire the consumer first.');
   else{await db.exec('ALTER TABLE profiles DROP COLUMN IF EXISTS full_name');trace.push('A schema contraction was attempted while an old reader remained.');}
   await probe('After contract decision','Version 1','SELECT full_name FROM profiles WHERE id=1');
  }
  const cols=await db.query("SELECT column_name FROM information_schema.columns WHERE table_name='profiles' ORDER BY ordinal_position");
  return {title:safe?'Keep the compatibility window open':'The application changed before its consumers',summary:'The SQL and client queries execute on actual PostgreSQL. Traffic, readiness, and deployment phases are an explicit browser model; no cloud resources are changed.',metrics:[['Failed data reads',failed],['Columns retained',cols.rows.length]],trace,tables:[{title:'Executed client checks',columns:['Phase','Consumer','Status','Actual result'],rows:checks},{title:'Final database columns',columns:['Column'],rows:cols.rows.map(r=>[r.column_name])}],code:safe?expandSQL:'ALTER TABLE profiles RENAME COLUMN full_name TO display_name;'};
 }finally{await db.close();}
}
