// Camada de UI de autorização (Control Center). Só decide o que é exibido; a decisão de segurança é do banco (RLS + private.has_permission).
// A UI consulta window.VxAuthorization.can() (RPC public.authorize). Enquanto a migration 0015 não estiver aplicada no Supabase remoto,
// essa RPC está aplicada e validada no remoto; os guardas agora podem operar em modo fail-closed.
const VX_RBAC_ENFORCED = true;

// Fora de um AccessProvider nada é permitido (fail-closed).
const VxAccessCtx = React.createContext({ status: 'loading', enforced: true, orgKind: null, can: () => false, allows: () => false });

// Regra única de visibilidade de uma tela/menu: permissão + escopo pelo tipo da organização ativa.
// scope 'internal' = só organização VERTICE; scope 'client' = qualquer organização que não seja a VERTICE.
// Sem tipo de organização conhecido (contexto indisponível) nada com escopo é exibido (fail-closed).
function vxScopeOk(scope, orgKind) {
  if (!scope) return true;
  if (!orgKind) return false;
  return scope === 'internal' ? orgKind === 'VERTICE' : scope === 'client' ? orgKind !== 'VERTICE' : false;
}
const useAccess = () => React.useContext(VxAccessCtx);

function AccessProvider({ permissions, children }) {
  const [state, setState] = React.useState(() => VX_RBAC_ENFORCED ? { status: 'loading', allowed: {}, orgKind: null } : { status: 'ready', allowed: null, orgKind: null });
  const keys = (permissions || []).join('|');
  // Recarrega as permissões quando o contexto ativo muda (login, logout, troca de ambiente).
  const [ctxVersion, setCtxVersion] = React.useState(0);
  React.useEffect(() => {
    const bump = () => setCtxVersion(v => v + 1);
    window.addEventListener('vx-context-changed', bump);
    return () => window.removeEventListener('vx-context-changed', bump);
  }, []);
  React.useEffect(() => {
    if (!VX_RBAC_ENFORCED) return;
    let alive = true;
    setState({ status: 'loading', allowed: {}, orgKind: null });
    const list = keys ? keys.split('|') : [];
    // Fail-closed: erro, RPC ausente ou resposta diferente de true => negado.
    const perms = Promise.all(list.map(p => window.VxAuthorization.can(p).then(r => [p, !!(r && r.allowed)], () => [p, false])));
    // Tipo da organização ativa (VERTICE, CLIENT...), vindo do contexto do servidor.
    const kind = window.VxAuthorization.getContext().then(ctx => {
      const active = ctx && ctx.active_context;
      const m = ((ctx && ctx.memberships) || []).find(x => x.organization && active && x.organization.id === active.organization_id);
      return (m && m.organization && m.organization.kind) || null;
    }, () => null);
    Promise.all([perms, kind]).then(([rs, orgKind]) => { if (alive) setState({ status: 'ready', allowed: Object.fromEntries(rs), orgKind }); });
    return () => { alive = false; };
  }, [keys, ctxVersion]);
  const value = React.useMemo(() => {
    const can = p => !p || !VX_RBAC_ENFORCED || (state.allowed && state.allowed[p] === true);
    return {
      status: state.status,
      enforced: VX_RBAC_ENFORCED,
      orgKind: state.orgKind,
      can,
      allows: it => !it || (can(it.perm) && (!VX_RBAC_ENFORCED || vxScopeOk(it.scope, state.orgKind))),
    };
  }, [state]);
  return <VxAccessCtx.Provider value={value}>{children}</VxAccessCtx.Provider>;
}

// hide: sem a permissão, não renderiza.
function Can({ perm, children, fallback = null }) {
  return useAccess().can(perm) ? children : fallback;
}

// disable: botão visível, desabilitado, com cadeado e tooltip.
function PBtn({ perm, icon, onClick, children, ...rest }) {
  const { Button, Tooltip } = window.VRticeDesignSystem_d763eb;
  const ok = useAccess().can(perm);
  const b = <Button {...rest} icon={ok ? icon : 'ph-lock-simple'} onClick={ok ? onClick : undefined} disabled={!ok || rest.disabled}>{children}</Button>;
  return ok ? b : <Tooltip content={'Requer ' + perm + '. Solicite acesso a um administrador.'} placement="bottom" width={260}>{b}</Tooltip>;
}

// não disponível (sem relação com permissão): botão desabilitado + "Em breve".
function SoonBtn({ children, ...rest }) {
  const { Button, Badge } = window.VRticeDesignSystem_d763eb;
  return <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}><Button {...rest} disabled>{children}</Button><Badge variant="meta" tone="neutral">Em breve</Badge></span>;
}

// Dados ilustrativos: telas ainda sem backend mostram este aviso para que nenhum número,
// registro ou ação seja confundido com dado real da organização.
function DemoNotice({ children, title = 'Dados ilustrativos' }) {
  const { Alert } = window.VRticeDesignSystem_d763eb;
  return <Alert tone="info" title={title}>{children || 'Esta tela ainda não está ligada ao banco. Os números e registros abaixo são exemplos e as ações não são gravadas.'}</Alert>;
}

// readonly
function ReadOnlyNote({ perm }) {
  const { Alert } = window.VRticeDesignSystem_d763eb;
  if (useAccess().can(perm)) return null;
  return <Alert tone="info" title="Modo somente leitura">Seu papel permite visualizar, mas não alterar estes dados. A autorização final é validada no servidor.</Alert>;
}

// lock / denied: tela 403.
function LockedState({ perm, kind = 'denied', go, home }) {
  const { Card, Button } = window.VRticeDesignSystem_d763eb;
  const locked = kind === 'locked';
  return (
    <Card variant="panel" padding="56px 32px" style={{ alignItems: 'center', textAlign: 'center', gap: 16 }}>
      <span style={{ width: 64, height: 64, borderRadius: 18, background: 'color-mix(in srgb, var(--status-warning) 14%, transparent)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><i className={'ph ' + (locked ? 'ph-lock-simple' : 'ph-shield-slash')} style={{ fontSize: 30, color: 'var(--status-warning)' }} /></span>
      <span style={{ fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--text-subtle)', fontWeight: 600 }}>{locked ? 'MÓDULO BLOQUEADO' : 'ACESSO NEGADO'} · 403</span>
      <h2 style={{ margin: 0, fontSize: 24, fontWeight: 600, letterSpacing: '-0.02em' }}>{locked ? 'Seu papel não inclui este módulo' : 'Você não tem autorização para esta ação'}</h2>
      <p style={{ margin: 0, maxWidth: 480, fontSize: 14, color: 'var(--text-muted)', lineHeight: 1.5 }}>A decisão é tomada pelo servidor a cada requisição. Para obter este acesso, peça a um administrador da sua organização ou ao proprietário da plataforma.</p>
      {perm && <span style={{ fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--text-accent)', background: 'var(--overlay-05)', borderRadius: 8, padding: '6px 12px' }}>{perm}</span>}
      {home && <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', justifyContent: 'center' }}><Button onClick={() => go(home.id)}>Ir para {home.label}</Button></div>}
    </Card>
  );
}

function SkeletonPage() {
  const { Card, Skeleton } = window.VRticeDesignSystem_d763eb;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 28 }} aria-busy="true" aria-label="Carregando">
      <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}><Skeleton width={120} height={11} /><Skeleton width="40%" height={34} radius={10} /><Skeleton width="55%" height={13} /></div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(200px,1fr))', gap: 16 }}>{[0, 1, 2, 3].map(k => <Skeleton key={k} height={104} radius={20} />)}</div>
      <Card variant="flat" padding={24} gap={16}>{[0, 1, 2, 3, 4, 5].map(k => <div key={k} style={{ display: 'flex', gap: 16, alignItems: 'center' }}><Skeleton width={36} height={36} radius={999} /><Skeleton width="30%" height={13} /><Skeleton width="18%" height={13} /><Skeleton width="12%" height={13} /></div>)}</Card>
    </div>
  );
}

// Resolve, acima do conteúdo da rota: carregando permissões e acesso negado/bloqueado.
// Estados de dados (vazio, erro, offline…) entram aqui quando as telas lerem dados reais.
function PageStateGuard({ meta, go, children }) {
  const { status, allows } = useAccess();
  if (status === 'loading') return <SkeletonPage />;
  if (meta && !allows(meta)) {
    // Primeira tela que o usuário pode ver (o Dashboard não é o início de todo mundo: ex.: auditor externo).
    const home = window.VX_NAV.groups.flatMap(g => g.items).find(allows) || null;
    return <LockedState perm={meta.perm} kind={meta.deny === 'lock' ? 'locked' : 'denied'} go={go} home={home} />;
  }
  return children;
}

class VxBoundary extends React.Component {
  constructor(p) { super(p); this.state = { e: null }; }
  static getDerivedStateFromError(e) { return { e }; }
  componentDidUpdate(p) { if (p.k !== this.props.k && this.state.e) this.setState({ e: null }); }
  render() {
    const { Alert } = window.VRticeDesignSystem_d763eb;
    return this.state.e ? <Alert tone="danger" title="Esta tela não pôde ser exibida">{String(this.state.e.message || this.state.e)}</Alert> : this.props.children;
  }
}

Object.assign(window, { VX_RBAC_ENFORCED, vxScopeOk, useAccess, AccessProvider, Can, PBtn, SoonBtn, DemoNotice, ReadOnlyNote, LockedState, SkeletonPage, PageStateGuard, VxBoundary });
