import {buildOfferPackage} from '@/lib/iva-offer-package'; import {useRef,useState} from 'react'; import {emptyOfferRequest,offerRequestLabels,type OfferPreparation} from '@/lib/iva-offer-preparations'; import {emptyOfferWorkflow,offerWrittenRequest,offerWorkflowSource,offerWorkflowApplied,recordOfferWorkflow,offerAttachmentValid,type OfferAttachment,type OfferWorkflow} from '@/lib/iva-offer-workflow'; export function SimulationOfferWorkflow({row,draft,onChange}:{row:OfferPreparation;draft:Record;onChange:(patch:Partial)=>void}){ const stageLabels:Record={request:'Pedido em preparação',presented:'Pedido apresentado',decision:'Decisão recebida',form:'Formulário preparado'};const latest=useRef(row);latest.current=row;const[notice,setNotice]=useState('');const[error,setError]=useState(''),[busy,setBusy]=useState(false),[documents,setDocuments]=useState([]),[draftId,setDraftId]=useState('');const w=row.workflow??emptyOfferWorkflow(); const edit=(patch:Partial)=>onChange({workflow:{...(latest.current.workflow??emptyOfferWorkflow()),...patch}}); const action=async(fn:()=>void|Promise)=>{setBusy(true);try{await fn();setError('');}catch(e){setError(String(e));}finally{setBusy(false);}}; const current=async()=>{const response=await fetch('/api/v1/simulation-drafts/current',{credentials:'same-origin',cache:'no-store',headers:{Accept:'application/json'}});if(!response.ok)throw Error('Não foi possível localizar a gravação privada.');const data=(await response.json()).data;if(!data?.id)throw Error('Guarde primeiro o rascunho no portal para lhe associar anexos privados.');if(data.economic_snapshot?.context_opportunity!==draft.context_opportunity)throw Error('A gravação actual pertence a outro contexto;guarde este rascunho antes de anexar.');setDraftId(data.id);return data.id as string;}; const list=async()=>{const id=await current(),response=await fetch(`/api/v1/simulation-drafts/${id}/offer-documents`,{credentials:'same-origin',headers:{Accept:'application/json'}});if(response.status===401||response.status===403)throw Error('Autentique-se para anexar ou consultar documentos privados;os dados preparados mantêm-se.');if(!response.ok)throw Error('Não foi possível recuperar anexos privados.');setDocuments((await response.json()).data);}; const attach=async(file:File,field:'requestAttachment'|'decisionAttachment'|'formAttachment')=>{const id=await current(),data=new FormData();data.append('file',file);const csrf=document.querySelector('meta[name="csrf-token"]')?.content;const xsrf=document.cookie.split('; ').find(c=>c.startsWith('XSRF-TOKEN='))?.slice(11);const response=await fetch(`/api/v1/simulation-drafts/${id}/offer-documents`,{method:'POST',credentials:'same-origin',headers:{Accept:'application/json',...(csrf?{'X-CSRF-TOKEN':csrf}:{}),...(xsrf?{'X-XSRF-TOKEN':decodeURIComponent(xsrf)}:{})},body:data});if(!response.ok)throw Error(response.status===401?'Autentique-se para guardar anexos privados.':'Anexo não confirmado;rascunho preservado. '+(await response.text()).slice(0,250));const doc=(await response.json()).data;if(!offerAttachmentValid(doc))throw Error('Confirmação do anexo inválida.');edit({[field]:doc});setDocuments(previous=>[...previous.filter(d=>d.id!==doc.id),doc]);}; const download=(blob:Blob,name:string)=>{const url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download=name;a.click();setTimeout(()=>URL.revokeObjectURL(url),1000);}; const packageForm=async()=>{const result=await buildOfferPackage(latest.current,async(url)=>{const response=await fetch(url,{credentials:'same-origin'});if(!response.ok)throw Error('Anexo conservado;aguarde análise antimalware concluída antes de descarregar o conjunto.');return response.arrayBuffer();});download(new Blob([Uint8Array.from(result.bytes).buffer],{type:'application/zip'}),`${row.branch}-pedido-decisao-formulario.zip`);onChange({workflow:result.row.workflow});setNotice('Conjunto preparado com pedido,elementos do formulário e despacho original conferido porSHA256;descarga iniciada.Submissão à autoridade permanece externa.');}; const text=(field:'recipient'|'writtenRequest'|'decisionIssuer'|'formName'|'formSource'|'formContent'|'submissionReference',label:string)=>