"""Validação visual isolada com APIs sintéticas (sem rede do Chromium). Testes reais da API: npm test."""
from pathlib import Path
from playwright.sync_api import sync_playwright
ROOT=Path(__file__).resolve().parents[1]
OUT=ROOT/'previews';OUT.mkdir(exist_ok=True)
css=(ROOT/'public/app.css').read_text()
js=(ROOT/'public/app.js').read_text()
html=(ROOT/'public/index.html').read_text().replace('<link rel="stylesheet" href="/app.css">',f'<style>{css}</style>')
mock=r'''
const patients=['Mariana Oliveira','Lucas Ferreira','Ana Beatriz Costa','Roberto Almeida','Camila Santos','Pedro Henrique Lima','Fernanda Rocha','Gabriel Martins'].map((name,i)=>({id:i+1,name,phone:'(11) 99999-1234',birth_date:'1989-03-15',active:1,cpf:'',email:'',notes:'Fictício',appointments:[],encounters:[],documents:[]}));
const current={id:1,name:'Dra. Aurora',role:'admin',email:'aurora@example.test',clinic:'Clínica Exemplo',crm:'',uf:''};
const doctors=[{...current,active:1}],docRecords=[],encRecords=[],templates=[];
let logged=true;
let nextId=20;
const response=(data,status=200)=>({ok:status<400,status,json:async()=>data});
const now=new Date(),iso=n=>{let d=new Date(now);d.setDate(d.getDate()+n);return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0')+'T09:30'};
const appointments=[{id:1,starts_at:iso(0),patient:'Mariana Oliveira',patient_id:1,doctor:'Dra. Aurora',doctor_id:1,kind:'Consulta',duration:30,status:'confirmado'},{id:2,starts_at:iso(1),patient:'Lucas Ferreira',patient_id:2,doctor:'Dra. Aurora',doctor_id:1,kind:'Retorno',duration:30,status:'agendado'}];
history.pushState=()=>{};
window.fetch=async function(url,opts={}){let path=String(url).replace(/^\/api/,''),method=opts.method||'GET',payload=opts.body?JSON.parse(opts.body):{};
 if(path==='/session')return response({configured:true,authenticated:logged,csrf:'fake',user:current});
 if(path==='/dashboard')return response({stats:{patients:8,today:1,upcoming:2,documents:docRecords.length},upcoming:appointments,recent:encRecords,chart:Array.from({length:6},(_,i)=>({month:'2026-'+String(i+4).padStart(2,'0'),count:i+3}))});
 if(path.startsWith('/patients/')){let id=Number(path.split('/')[2]),p=patients.find(x=>x.id===id);return response({...p,appointments:appointments.filter(a=>a.patient_id===id),documents:docRecords.filter(a=>a.patient_id===id),encounters:encRecords.filter(a=>a.patient_id===id)});}
 if(path.startsWith('/patients'))return response(patients);
 if(path.startsWith('/doctors'))return response(doctors);
 if(path.startsWith('/appointments'))return response(appointments);
 if(path.startsWith('/encounters/')){let id=Number(path.split('/')[2]);if(path.includes('versions'))return response([{revision:1,snapshot:JSON.stringify({reason:'Fictício',status:'rascunho'}),created_at:'2026-10-08'}]);return response(encRecords.find(x=>x.id===id));}
 if(path.startsWith('/encounters')){if(method==='POST'){let item={...payload,id:nextId++,doctor:'Dra. Aurora',doctor_id:1,patient:patients.find(x=>x.id===payload.patient_id)?.name,created_at:iso(0),version:1};encRecords.push(item);return response({id:item.id},201);}return response(encRecords);}
 if(path.startsWith('/documents/')){let id=Number(path.split('/')[2]);if(path.includes('versions'))return response([]);return response(docRecords.find(x=>x.id===id));}
 if(path.startsWith('/documents')){if(method==='POST'){let item={...payload,id:nextId++,doctor:'Dra. Aurora',doctor_id:1,patient:patients.find(x=>x.id===payload.patient_id)?.name,created_at:iso(0),version:1};docRecords.push(item);return response({id:item.id},201);}return response(docRecords);}
 if(path.startsWith('/templates')){if(method==='POST'){templates.push({...payload,id:nextId++});return response({ok:true},201);}return response(templates);}
 if(path.startsWith('/triages'))return response([]);
 if(path.startsWith('/audit'))return response([]);
 if(path==='/logout'){logged=false;return response({ok:true});}
 return response({error:'Rota mock não definida: '+path},404);
};
'''
html=html.replace('<script type="module" src="/app.js"></script>',f'<script>{mock}</script><script>{js}</script>')
with sync_playwright() as p:
    browser=p.chromium.launch(headless=True,executable_path='/usr/bin/chromium',args=['--no-sandbox'])
    page=browser.new_page(viewport={'width':390,'height':844},is_mobile=True,has_touch=True,device_scale_factor=1)
    errs=[]
    page.on('pageerror',lambda e:errs.append(str(e)))
    page.set_content(html,wait_until='load')
    page.wait_for_selector('.compact-hero')
    page.screenshot(path=str(OUT/'mobile-home.png'),full_page=True)
    page.locator('button[data-go="patients"]').last.click()
    page.wait_for_selector('.patient-mobile-card')
    assert page.locator('.patient-mobile-card').count()==8
    page.screenshot(path=str(OUT/'mobile-patients.png'),full_page=True)
    page.locator('.patient-mobile-card').first.click()
    page.wait_for_selector('.modal-backdrop')
    page.locator('button[data-action="close-modal"]').last.click()
    page.locator('button[data-go="agenda"]').last.click()
    page.wait_for_selector('.agenda-controls')
    page.locator('button[data-action="agenda-mode"][data-value="semana"]').click()
    page.wait_for_selector('.week-layout')
    page.locator('button[data-action="agenda-mode"][data-value="mes"]').click()
    page.wait_for_selector('.month-calendar')
    page.screenshot(path=str(OUT/'mobile-agenda.png'),full_page=True)
    page.locator('button[data-go="more"]').click()
    page.locator('button[data-go="documents"]').last.click()
    page.locator('button[data-action="manage-templates"]').click()
    page.locator('button[data-action="new-template"]').click()
    page.locator('input[name="name"]').fill('Modelo exemplo')
    page.locator('textarea[name="body"]').fill('Texto de demonstração. Documento NÃO válido.')
    page.locator('form[data-form="template"] button[type="submit"]').click()
    page.locator('button[data-action="new-doc"]').click()
    page.locator('select[name="template_id"]').select_option(label='Modelo exemplo')
    assert page.locator('textarea[name="body"]').input_value().startswith('Texto de demonstração')
    page.locator('select[name="patient_id"]').select_option(index=1)
    page.locator('form[data-form="document"] button[type="submit"]').click()
    page.wait_for_selector('button[data-action="edit-doc"]')
    page.locator('button[data-go="more"]').click()
    page.locator('button[data-go="encounters"]').last.click()
    page.locator('button[data-action="new-encounter"]').click()
    page.locator('select[name="patient_id"]').select_option(index=1)
    page.locator('textarea[name="reason"]').fill('Atendimento fictício')
    page.locator('textarea[name="assessment"]').fill('Avaliação fictícia')
    page.locator('textarea[name="plan"]').fill('Conduta fictícia')
    page.locator('select[name="status"]').select_option('finalizado')
    page.locator('input[name="confirm_finalize"]').check()
    page.locator('form[data-form="encounter"] button[type="submit"]').click()
    page.wait_for_selector('button[data-action="edit-encounter"]')
    page.set_viewport_size({'width':320,'height':700})
    assert not page.evaluate('document.documentElement.scrollWidth > window.innerWidth+2'),'Overflow 320 px'
    assert not errs,errs
    desktop=browser.new_page(viewport={'width':1440,'height':900})
    desktop.on('pageerror',lambda e:errs.append(str(e)))
    desktop.set_content(html,wait_until='load')
    desktop.wait_for_selector('.compact-hero')
    desktop.screenshot(path=str(OUT/'desktop-home.png'),full_page=True)
    assert not errs,errs
    print('APROVADO VISUAL (API sintética): dashboard, 8 cartões pacientes, ficha, agenda semana/mês, modelo, documento, finalização, 320px, desktop, sem JS errors')
    for path in OUT.glob('*.png'):print(path.name, path.stat().st_size, 'bytes')
    browser.close()
