import React,{useEffect,useMemo,useState,useRef} from 'react';
import {statementDownload} from './statement-download.js';
import {WorkshopStockOperation} from './workshop-stock-operation.js';
import {minorAmount} from './ledger-report-view.js';
import {checkedStatements,statementCategories,statementStates} from './internal-statements-view.js';
const qs=q=>new URLSearchParams(Object.entries(q).filter(([,v])=>v!==''&&v!==null)).toString();
export function StatementGroups({summary}){const cards=(currency,c,categories)=>
Capital e equação patrimonial completa: indeterminados. Balanço completo: não.
Resultados internos parciais
{cards(currency,c,['income','expense'])}
Subtotal das rubricas de resultados classificadas: {minorAmount(c.known_result_subtotal_minor)} {currency}. Não é resultado da empresa.
Resultado completo: {c.complete_result_minor===null?'Indeterminado por classificação pendente':minorAmount(c.complete_result_minor)+' '+currency+' no recorte QA'}.
Contas por classificar
{cards(currency,c,['unclassified'])}
{c.unclassified_accounts} conta(s) por classificar; o saldo conserva o sinal original.
)};}
export function StatementLines({rows,dates}){return
;}
export default function InternalStatementsWorkspace({api,context}){
const[query,setQuery]=useState({view:'history',page:1,per_page:25}),[data,setData]=useState(null),[form,setForm]=useState(null),[preview,setPreview]=useState(null),[busy,setBusy]=useState(false),[error,setError]=useState(''),[notice,setNotice]=useState(''),[accounts,setAccounts]=useState(null),[optionQuery,setOptionQuery]=useState({view:'accounts',page:1,per_page:25,search:''}),[search,setSearch]=useState(''),[accountId,setAccountId]=useState(''),[category,setCategory]=useState(''),[receiptKey,setReceiptKey]=useState(''),[receipt,setReceipt]=useState(null);
const mounted=useRef(true),generation=useRef(context.token);generation.current=context.token;useEffect(()=>{mounted.current=true;return()=>{mounted.current=false;};},[context.token]);
const command=useMemo(()=>new WorkshopStockOperation(api),[context.token]),locked=busy||command.uncertain;
useEffect(()=>{let active=true;setData(null);setBusy(true);setError('');api('/api/general-ledger/statements?'+qs(query)).then(r=>{if(active)setData(checkedStatements(r,query));}).catch(e=>{if(active)setError(e.message);}).finally(()=>{if(active)setBusy(false);});return()=>{active=false;};},[context.token,query]);
useEffect(()=>{if(form?.kind!=='mapping'||form.action!=='prepare')return;let active=true;setAccounts(null);api('/api/general-ledger/statements?'+qs(optionQuery)).then(r=>{if(active)setAccounts(checkedStatements(r,optionQuery).records);}).catch(e=>{if(active)setError(e.message);});return()=>{active=false;};},[context.token,optionQuery,form?.kind,form?.action]);
function start(kind,action){setPreview(null);setError('');setReceipt(null);const latest=kind==='mapping'?data.mapping_latest:data.result_latest;setForm({kind,action,version:latest?.version??0,reason:'',data:action==='review'?{decision:''}:kind==='mapping'?{entries:(data.mapping_approved?.data.entries??[]).map(e=>({account_id:e.account_id,category:e.category})),evidence:''}:{mapping_id:'',from_on:'',to_on:'',per_page:25,evidence:''}});setAccountId('');setCategory('');}
function addEntry(){const id=Number(accountId);if(!Number.isSafeInteger(id)||!category||!accounts?.data.some(a=>a.id===id))return;setForm(f=>({...f,data:{...f.data,entries:[...f.data.entries.filter(e=>e.account_id!==id),{account_id:id,category}]}}));setAccountId('');setCategory('');}
async function prepare(e){e.preventDefault();setBusy(true);setError('');try{const input=structuredClone(form);if(input.kind==='result'&&input.action==='prepare'){input.data.mapping_id=Number(input.data.mapping_id);input.data.per_page=Number(input.data.per_page);}const key=crypto.randomUUID(),out=await api('/api/general-ledger/statements/preview','POST',input,undefined,key);setPreview({...out,key});}catch(e){setError(e.message);}finally{setBusy(false);}}
async function confirm(retry=false){setBusy(true);setError('');try{const out=retry?await command.retry():await command.send('/api/general-ledger/statements/confirm',{preview:preview.preview},preview.key);setReceiptKey(preview.key);setNotice(out.kind+' v'+out.version+' · '+statementStates[out.state]+(out.replayed?' · recibo recuperado':''));setForm(null);setPreview(null);setQuery({view:'history',page:1,per_page:query.per_page});}catch(e){setError(e.message);if(!command.uncertain)setPreview(null);}finally{setBusy(false);}}
async function recover(){setBusy(true);setError('');try{setReceipt(await api('/api/general-ledger/statements/receipts/'+encodeURIComponent(receiptKey)));}catch(e){setError(e.message);}finally{setBusy(false);}}
async function download(){const token=context.token;setBusy(true);setError('');try{const result=await statementDownload({id:query.version_id,token,sha256:data.snapshot.csv_sha256,isCurrent:()=>mounted.current&&generation.current===token});const url=URL.createObjectURL(new Blob([result.bytes],{type:'text/csv;charset=utf-8'}));const a=document.createElement('a');a.href=url;a.download='sgf-demonstracoes-internas-QA.csv';a.click();setTimeout(()=>URL.revokeObjectURL(url),1000);setNotice('CSV congelado descarregado e SHA verificado.');}catch(e){if(mounted.current&&generation.current===token)setError(e.message);}finally{if(mounted.current&&generation.current===token)setBusy(false);}}
const kindLabel=k=>k==='mapping'?'Correspondências':'Resultado interno';
return
CONTABILIDADE
Demonstrações internas parciais QA
Balanço e resultados por correspondências explícitas revistas. Sem classificação automática de contas, capital fabricado ou modelo legal. Os lançamentos originais não são alterados.
{data.current_source_matches?'A fonte actual confere com este resultado conservado.':'A fonte/correspondência actual difere; este resultado permanece histórico e não foi recalculado.'}
{r.data.summary.query.from_on} a{r.data.summary.query.to_on} · {r.data.summary.accounts} contas da fonte · {r.data.evidence}
{r.state==='approved'&&}>}
)}
}
Página{data.records.current_page} de{data.records.last_page} · {data.records.total} linha(s). Totais do resultado conservado abrangem todas as páginas da fonte; a tabela é paginada.
>}
{form&&}
{preview&&
Impacto a confirmar
Antes v{preview.impact.before.version} · {statementStates[preview.impact.before.state]??'Sem versão'}; depois v{preview.impact.after.version} · {statementStates[preview.impact.after.state]}. Zero lançamentos e contas alterados. Fundamento:{form.reason}.