<?php $title = 'Admin: Tenants'; ?>

<div class="card" style="width:98%;margin:0 auto;">
    <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;">
        <h1>Painel de Tenants</h1>
    </div>

    <div class="alert alert-error" id="error" style="display:none;"></div>
    <div class="alert alert-success" id="success" style="display:none;"></div>

    

    <div id="tabs" style="display:flex;gap:0.5rem;border-bottom:1px solid #e5e7eb;margin-bottom:0.75rem;flex-wrap:wrap;">
        <button class="tab-btn active" data-tab="dashboard">Dashboard</button>
        <button class="tab-btn" data-tab="tenants">Tenants</button>
        <button class="tab-btn" data-tab="plans">Planos</button>
        <button class="tab-btn" data-tab="finance">Financeiro</button>
        <button class="tab-btn" data-tab="modules">Módulos</button>
        <button class="tab-btn" data-tab="reports">Relatórios</button>
    </div>
    <style>
        .tab-btn { background:#fff;border:1px solid #e5e7eb;border-bottom:none;padding:0.5rem 0.75rem;border-radius:6px 6px 0 0;cursor:pointer; }
        .tab-btn.active { background:#f9fafb; font-weight:600; }
        .tab-panel { display:none; }
        .tab-panel.active { display:block; }
        /* Layout e responsividade */
        .card { box-sizing: border-box; }
        .table-responsive { overflow-x: auto; }
        .table { width: 100%; border-collapse: collapse; }
        .table th, .table td { padding: 0.5rem; vertical-align: middle; }
        @media (max-width: 992px) {
            #panel-tenants > div:first-of-type { flex-wrap: wrap; }
            #panel-tenants .table-responsive { overflow-x: auto; }
        }
        @media (max-width: 640px) {
            #panel-tenants input,
            #panel-tenants select,
            #panel-tenants button { width: 100%; }
            .tab-btn { font-size: 0.9rem; padding: 0.4rem 0.6rem; }
        }
    </style>

    <div id="panel-dashboard" class="tab-panel active">
        <h2 style="margin-top:0.5rem;margin-bottom:0.5rem;">Indicadores</h2>
        <div id="kpis" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:0.75rem;margin-bottom:0.75rem;">
            <div class="card" style="padding:0.75rem;">
                <div class="muted">Total de Tenants</div>
                <div id="kpiTotal" style="font-size:1.5rem;font-weight:700;">-</div>
            </div>
            <div class="card" style="padding:0.75rem;">
                <div class="muted">Ativos</div>
                <div id="kpiActive" style="font-size:1.5rem;font-weight:700;">-</div>
            </div>
            <div class="card" style="padding:0.75rem;">
                <div class="muted">Suspensos</div>
                <div id="kpiSuspended" style="font-size:1.5rem;font-weight:700;">-</div>
            </div>
            <div class="card" style="padding:0.75rem;">
                <div class="muted">Último Recebimento (mês)</div>
                <div id="kpiRevenue" style="font-size:1.5rem;font-weight:700;">R$ 0,00</div>
            </div>
        </div>
        <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:0.75rem;">
            <div class="card" style="padding:0.75rem;">
                <strong>Alertas</strong>
                <ul id="alerts" style="margin-top:0.5rem;"></ul>
            </div>
            <div class="card" style="padding:0.75rem;">
                <strong>Tenants por plano</strong>
                <canvas id="chartPlans" width="500" height="240" style="max-width:100%;"></canvas>
            </div>
            <div class="card" style="padding:0.75rem;">
                <strong>Cadastros por mês</strong>
                <canvas id="chartSignups" width="500" height="240" style="max-width:100%;"></canvas>
            </div>
        </div>
    </div>

    <div id="panel-tenants" class="tab-panel">
    <h2 style="margin-top:1rem;margin-bottom:0.5rem;">Tenants</h2>
    <div style="display:flex;gap:0.75rem;margin-bottom:1rem;align-items:center;flex-wrap:wrap;">
        <button id="refreshBtn" class="btn btn-secondary">Atualizar</button>
        <button id="printTenantsBtn" class="btn btn-secondary">Imprimir PDF</button>
        <input id="searchInput" type="text" placeholder="Buscar por id/nome/email/domínio" style="min-width:260px;flex:1;" />
        <select id="statusFilter" style="min-width:140px;">
            <option value="">Status: Todos</option>
            <option value="active">Ativos</option>
            <option value="suspended">Suspensos</option>
        </select>
        <select id="planFilter" style="min-width:160px;">
            <option value="">Plano: Todos</option>
        </select>
        <input id="domainFilter" type="text" placeholder="Filtrar por domínio" style="min-width:220px;" />
        <span style="font-size:0.9rem;">De</span>
        <input id="dateFrom" type="date" aria-label="Data inicial" title="Data inicial" />
        <span style="font-size:0.9rem;">Até</span>
        <input id="dateTo" type="date" aria-label="Data final" title="Data final" />
        <span style="flex:1"></span>
    </div>
    <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:0.75rem;margin-bottom:1rem;align-items:center;">
        <input id="newTenantRazaoSocial" type="text" placeholder="Razão Social (obrigatório)" minlength="5" maxlength="100" />
        <input id="newTenantName" type="text" placeholder="Nome fantasia" />
        <select id="newTenantTipo">
            <option value="">Tipo: PF/PJ</option>
            <option value="PF">PF</option>
            <option value="PJ">PJ</option>
        </select>
        <input id="newTenantCpf" type="text" placeholder="CPF (PF)" />
        <input id="newTenantCnpj" type="text" placeholder="CNPJ (PJ)" />
        <input id="newTenantIE" type="text" placeholder="Inscrição Estadual (XX.XXX.XXX-X)" />
        <input id="newTenantEmail" type="email" placeholder="Email de contato (opcional)" />
        <select id="newTenantPlan"><option value="">Plano: nenhum</option></select>
        <input id="newTenantId" type="text" placeholder="tenant_id (opcional, será gerado)" />
        <input id="newTenantCep" type="text" placeholder="CEP" />
        <select id="newTenantTipoLogradouro">
            <option value="">Tipo de logradouro</option>
            <option value="Rua">Rua</option>
            <option value="Avenida">Avenida</option>
            <option value="Travessa">Travessa</option>
            <option value="Viela">Viela</option>
            <option value="Alameda">Alameda</option>
            <option value="Estrada">Estrada</option>
            <option value="Rodovia">Rodovia</option>
            <option value="Praça">Praça</option>
            <option value="Largo">Largo</option>
        </select>
        <input id="newTenantLogradouro" type="text" placeholder="Nome do logradouro (autocomplete)" list="logradouroList" />
        <datalist id="logradouroList"></datalist>
        <input id="newTenantNumero" type="text" placeholder="Número" />
        <input id="newTenantComplemento" type="text" placeholder="Complemento" />
        <input id="newTenantBairro" type="text" placeholder="Bairro" />
        <input id="newTenantCidade" type="text" placeholder="Cidade" />
        <input id="newTenantEstado" type="text" placeholder="UF" maxlength="2" />
        <input id="newTenantDomain" type="text" placeholder="Domínio (opcional)" />
        <button id="createBtn" class="btn">Criar tenant</button>
    </div>
    <div class="table-responsive">
        <table class="table" id="tenantsTable">
            <thead>
                <tr>
                    <th>Tenant</th>
                    <th>Nome</th>
                    <th>Domínio</th>
                    <th>Plano</th>
                    <th>Acesso</th>
                    <th>Status</th>
                    <th>Cadastro</th>
                    <th>Último Pagamento</th>
                    <th style="width:520px;">Ações</th>
                </tr>
            </thead>
            <tbody id="tenantsBody"></tbody>
        </table>
    </div>
    </div>

    <div id="panel-plans" class="tab-panel">
        <h2 style="margin-top:0.5rem;margin-bottom:0.5rem;">Planos</h2>
        <div id="plansSection"></div>
    </div>

    <div id="panel-finance" class="tab-panel">
        <h2 style="margin-top:0.5rem;margin-bottom:0.5rem;">Financeiro</h2>
        <div id="financeSection" class="table-responsive"></div>
    </div>

    <div id="panel-modules" class="tab-panel">
        <h2 style="margin-top:0.5rem;margin-bottom:0.5rem;">Módulos</h2>
        <div id="modulesSection" class="table-responsive"></div>
    </div>

    <div id="panel-reports" class="tab-panel">
        <h2 style="margin-top:0.5rem;margin-bottom:0.5rem;">Relatórios Gerenciais</h2>
        <div style="display:flex;gap:0.5rem;margin-bottom:0.75rem;">
            <button class="btn" id="exportCsvBtn">Exportar CSV</button>
            <button class="btn btn-secondary" id="printReportsBtn">Imprimir PDF</button>
        </div>
        <div id="reportsSection" class="table-responsive"></div>
    </div>

    
</div>

<script>
    function getAdminSecret() { return ''; }
    function setAdminSecret(s) { /* removido */ }
    function showError(msg) {
        const el = document.getElementById('error');
        el.textContent = msg || 'Falha';
        el.style.display = 'block';
        setTimeout(() => { el.style.display = 'none'; }, 5000);
    }
    function showSuccess(msg) {
        const el = document.getElementById('success');
        el.textContent = msg || 'Ok';
        el.style.display = 'block';
        setTimeout(() => { el.style.display = 'none'; }, 4000);
    }
    function setResult(obj) {
        try { console.log('Resultado:', obj); } catch (_) {}
    }

    function getAdminToken() {
        try {
            const ls = localStorage.getItem('admin_token');
            if (ls) return ls;
        } catch (_) {}
        const m = document.cookie.match(/(?:^|; )admin_token=([^;]+)/);
        return m ? decodeURIComponent(m[1]) : null;
    }
    async function callAdminApi(url, options = {}) {
        const headers = { ...(options.headers || {}) };
        const adminToken = getAdminToken();
        if (!adminToken) { showError('Faça login como admin.'); window.location.href = '/admin/login'; return null; }
        headers['Authorization'] = 'Bearer ' + adminToken;
        const resp = await apiRequest(url, { ...options, headers });
        return resp;
    }

    let cachedPlans = [];
    let cachedTenants = [];
    async function refreshTenants() {
        try {
            const [respSum, respPlans] = await Promise.all([
                callAdminApi('/api/admin/tenants/summary'),
                callAdminApi('/api/admin/plans')
            ]);
            if (!respSum || !respPlans) return;
            if (!respSum.ok) { showError('Falha ao listar tenants'); return; }
            const jsonSum = await respSum.json();
            cachedTenants = jsonSum.data || [];
            const jsonPlans = await respPlans.json();
            cachedPlans = (jsonPlans.data || []);
            renderPlansFilters();
            renderTenants();
            renderPlansList();
            renderDashboard();
            renderFinance();
            renderModules();
            renderReports();
            showSuccess(`Encontrados ${cachedTenants.length} tenants.`);
        } catch (e) { showError('Erro ao atualizar lista'); }
    }

    function switchTab(tab) {
        document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
        document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
        const btn = document.querySelector(`.tab-btn[data-tab="${tab}"]`);
        const panel = document.getElementById(`panel-${tab}`);
        if (btn && panel) { btn.classList.add('active'); panel.classList.add('active'); }
    }

    function renderPlansFilters() {
        const planSelect = document.getElementById('planFilter');
        const createPlanSelect = document.getElementById('newTenantPlan');
        planSelect.innerHTML = '<option value="">Plano: Todos</option>';
        createPlanSelect.innerHTML = '<option value="">Plano: nenhum</option>';
        for (const p of cachedPlans) {
            const opt = document.createElement('option'); opt.value = String(p.id); opt.textContent = p.name;
            planSelect.appendChild(opt);
            const opt2 = document.createElement('option'); opt2.value = String(p.id); opt2.textContent = p.name;
            createPlanSelect.appendChild(opt2);
        }
    }

    function renderTenants() {
        const tbody = document.getElementById('tenantsBody');
        tbody.innerHTML = '';
        const q = (document.getElementById('searchInput').value || '').toLowerCase();
        const st = document.getElementById('statusFilter').value || '';
        const pf = document.getElementById('planFilter').value || '';
        const df = (document.getElementById('domainFilter').value || '').toLowerCase();
        const dFrom = document.getElementById('dateFrom').value || '';
        const dTo = document.getElementById('dateTo').value || '';
        const tenants = cachedTenants.filter(t => {
            const hits = (t.tenant_id + ' ' + (t.name||'') + ' ' + (t.contact_email||'') + ' ' + (t.domain||'')).toLowerCase().includes(q);
            const bySt = st === '' || (t.status === st);
            const byPlan = pf === '' || (String(t.plan.id||'') === pf);
            const byDomain = df === '' || ((t.domain||'').toLowerCase().includes(df));
            const created = (t.created_at||'').slice(0,10);
            const byDateFrom = !dFrom || (created >= dFrom);
            const byDateTo = !dTo || (created <= dTo);
            return hits && bySt && byPlan && byDomain && byDateFrom && byDateTo;
        });
        for (const t of tenants) {
            const tr = document.createElement('tr');
            const tdName = document.createElement('td');
            tdName.textContent = t.tenant_id;
            const tdNome = document.createElement('td'); tdNome.textContent = t.name || '-';
            const tdDomain = document.createElement('td'); tdDomain.textContent = t.domain || '-';
            const tdPlano = document.createElement('td'); tdPlano.textContent = t.plan?.name || '-';
            const tdAccess = document.createElement('td'); tdAccess.textContent = t.access_enabled ? 'Liberado' : 'Bloqueado';
            const tdStatus = document.createElement('td'); tdStatus.textContent = t.status;
            const tdCreated = document.createElement('td'); tdCreated.textContent = (t.created_at||'').replace('T',' ').replace('.000Z','') || '-';
            const tdPay = document.createElement('td'); tdPay.textContent = t.last_payment ? `${t.last_payment.status} em ${t.last_payment.occurred_at}` : '-';
            const tdActions = document.createElement('td');
            tdActions.style.display = 'grid';
            tdActions.style.gridTemplateColumns = 'repeat(auto-fit, minmax(140px, 1fr))';
            tdActions.style.gap = '0.5rem';

            const btnAccess = document.createElement('button'); btnAccess.className = 'btn'; btnAccess.textContent = t.access_enabled ? 'Bloquear acesso' : 'Liberar acesso';
            btnAccess.addEventListener('click', () => toggleAccess(t.tenant_id, !t.access_enabled));

            const btnPayments = document.createElement('button'); btnPayments.className = 'btn'; btnPayments.textContent = 'Pagamentos';
            btnPayments.addEventListener('click', () => showPayments(t.tenant_id));

            const btnEdit = document.createElement('button'); btnEdit.className = 'btn'; btnEdit.textContent = 'Editar';
            btnEdit.addEventListener('click', () => openEditTenantModal(t));

            const btnSummary = document.createElement('button'); btnSummary.className = 'btn btn-secondary'; btnSummary.textContent = 'Resumo';
            btnSummary.addEventListener('click', () => openTenantSummary(t));

            const btnDelete = document.createElement('button'); btnDelete.className = 'btn btn-danger'; btnDelete.textContent = 'Excluir';
            btnDelete.addEventListener('click', () => confirmDeleteTenant(t.tenant_id));

            const btnImpersonate = document.createElement('button'); btnImpersonate.className = 'btn btn-secondary'; btnImpersonate.textContent = 'LOGAR COMO TENANT';
            btnImpersonate.addEventListener('click', () => impersonateTenant(t.tenant_id));

            const btnReset = document.createElement('button'); btnReset.className = 'btn'; btnReset.textContent = 'Redefinir senha';
            btnReset.addEventListener('click', () => openResetTenantPassword(t));

            tdActions.appendChild(btnAccess);
            tdActions.appendChild(btnPayments);
            tdActions.appendChild(btnEdit);
            tdActions.appendChild(btnSummary);
            tdActions.appendChild(btnImpersonate);
            tdActions.appendChild(btnReset);
            tdActions.appendChild(btnDelete);

            tr.appendChild(tdName);
            tr.appendChild(tdNome);
            tr.appendChild(tdDomain);
            tr.appendChild(tdPlano);
            tr.appendChild(tdAccess);
            tr.appendChild(tdStatus);
            tr.appendChild(tdCreated);
            tr.appendChild(tdPay);
            tr.appendChild(tdActions);
            tbody.appendChild(tr);
        }
    }

    async function createTenant() {
        const id = (document.getElementById('newTenantId').value || '').trim();
        const razao_social = (document.getElementById('newTenantRazaoSocial').value || '').trim();
        const ie_mask = (document.getElementById('newTenantIE').value || '').trim();
        const name = (document.getElementById('newTenantName').value || '').trim();
        const email = (document.getElementById('newTenantEmail').value || '').trim();
        const planId = (document.getElementById('newTenantPlan').value || '').trim();
        const domain = (document.getElementById('newTenantDomain').value || '').trim();
        const tipo = (document.getElementById('newTenantTipo').value || '').trim();
        const cpf = (document.getElementById('newTenantCpf').value || '').replace(/\D+/g,'');
        const cnpj = (document.getElementById('newTenantCnpj').value || '').replace(/\D+/g,'');
        const logradouro_tipo = (document.getElementById('newTenantTipoLogradouro').value || '').trim();
        const logradouro = (document.getElementById('newTenantLogradouro').value || '').trim();
        const numero = (document.getElementById('newTenantNumero').value || '').trim();
        const complemento = (document.getElementById('newTenantComplemento').value || '').trim();
        const bairro = (document.getElementById('newTenantBairro').value || '').trim();
        const cidade = (document.getElementById('newTenantCidade').value || '').trim();
        const estado = (document.getElementById('newTenantEstado').value || '').trim().toUpperCase();
        const cep = (document.getElementById('newTenantCep').value || '').replace(/\D+/g,'');
        const ie = ie_mask.replace(/\D+/g,'');
        try {
            // Validações básicas
            if (!razao_social || razao_social.length < 5 || razao_social.length > 100) { showError('Razão Social é obrigatória (5 a 100 caracteres)'); return; }
            if (ie && ie.length !== 9) { showError('Inscrição Estadual inválida (formato XX.XXX.XXX-X)'); return; }
            if (domain && !/^[a-z0-9][a-z0-9\-\.]*\.[a-z]{2,}$/i.test(domain)) { showError('Domínio inválido'); return; }
            if (tipo && !['PF','PJ'].includes(tipo)) { showError('Tipo inválido: PF ou PJ'); return; }
            if (tipo === 'PF' && cnpj) { showError('PF não deve informar CNPJ'); return; }
            if (tipo === 'PJ' && cpf) { showError('PJ não deve informar CPF'); return; }
            if (cpf && cpf.length !== 11) { showError('CPF inválido'); return; }
            if (cnpj && cnpj.length !== 14) { showError('CNPJ inválido'); return; }
            if (estado && !/^([A-Z]{2})$/.test(estado)) { showError('UF inválida'); return; }
            if (cep && !/^\d{8}$/.test(cep)) { showError('CEP inválido'); return; }
            const body = { razao_social, ie, name, contact_email: email, domain, tipo, cpf, cnpj, logradouro_tipo, logradouro, numero, complemento, bairro, cidade, estado, cep };
            if (id) body.tenant_id = id;
            if (planId) body.plan_id = planId;
            const resp = await callAdminApi('/api/admin/tenants', {
                method: 'POST',
                body: JSON.stringify(body)
            });
            if (!resp) return;
            const json = await resp.json();
            setResult(json);
            if (resp.ok) { showSuccess(`Tenant criado: ${json.tenant_id}`);
                document.getElementById('newTenantId').value='';
                document.getElementById('newTenantRazaoSocial').value='';
                document.getElementById('newTenantName').value='';
                document.getElementById('newTenantEmail').value='';
                document.getElementById('newTenantPlan').value='';
                document.getElementById('newTenantDomain').value='';
                document.getElementById('newTenantTipo').value='';
                document.getElementById('newTenantCpf').value='';
                document.getElementById('newTenantCnpj').value='';
                document.getElementById('newTenantIE').value='';
                document.getElementById('newTenantCep').value='';
                document.getElementById('newTenantTipoLogradouro').value='';
                document.getElementById('newTenantLogradouro').value='';
                document.getElementById('newTenantNumero').value='';
                document.getElementById('newTenantComplemento').value='';
                document.getElementById('newTenantBairro').value='';
                document.getElementById('newTenantCidade').value='';
                document.getElementById('newTenantEstado').value='';
                refreshTenants();
            }
            else { showError(json.error || 'Falha ao criar tenant'); }
        } catch (e) { showError('Erro ao criar tenant'); }
    }

    async function runMigrate(t) {
        try {
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(t)}/migrate`, { method: 'POST' });
            if (!resp) return;
            const json = await resp.json(); setResult(json);
            if (resp.ok) showSuccess('Migrações aplicadas'); else showError(json.error || 'Falha ao migrar');
        } catch (e) { showError('Erro nas migrações'); }
    }
    async function runModuleMigrate(t) {
        try {
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(t)}/migrate-modules`, { method: 'POST' });
            if (!resp) return;
            const json = await resp.json(); setResult(json);
            if (resp.ok) showSuccess('Migrações de módulos aplicadas'); else showError(json.error || 'Falha ao migrar módulos');
        } catch (e) { showError('Erro nas migrações de módulos'); }
    }
    async function runSeedAdmin(t) {
        try {
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(t)}/seed-admin`, { method: 'POST' });
            if (!resp) return;
            const json = await resp.json(); setResult(json);
            if (resp.ok) showSuccess('Admin seed concluído'); else showError(json.error || 'Falha ao semear admin');
        } catch (e) { showError('Erro ao semear admin'); }
    }
    async function runVerifyAdmin(t) {
        try {
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(t)}/verify-admin`);
            if (!resp) return;
            const json = await resp.json(); setResult(json);
            if (resp.ok && json.ok) showSuccess('Admin verificado'); else showError(json.error || 'Verificação falhou');
        } catch (e) { showError('Erro ao verificar admin'); }
    }
    async function runAuditAuth(t) {
        try {
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(t)}/audit-auth`);
            if (!resp) return;
            const json = await resp.json();
            const logs = (json.data || []).slice(0, 4);
            setResult({ total: (json.data || []).length, latest4: logs });
            if (resp.ok) showSuccess('Logs carregados'); else showError(json.error || 'Falha ao auditar');
        } catch (e) { showError('Erro ao ler logs'); }
    }

    async function impersonateTenant(t) {
        try {
            const resp = await callAdminApi('/api/admin/tenants/impersonate', {
                method: 'POST',
                body: JSON.stringify({ tenant_id: t }),
                credentials: 'same-origin'
            });
            if (!resp) return;
            // Aceitar 200/302 e redirecionar manualmente
            if (resp.ok || resp.status === 302) {
                showSuccess('Impersonate efetuado');
                window.location.href = '/clientes';
            } else {
                const json = await resp.json().catch(() => ({}));
                showError(json.error || 'Falha no impersonate');
            }
        } catch (e) { showError('Erro no impersonate'); }
    }

    function openResetTenantPassword(t) {
        const overlay = document.createElement('div'); overlay.style.position='fixed'; overlay.style.inset='0'; overlay.style.background='rgba(0,0,0,0.35)'; overlay.style.zIndex='1000';
        const modal = document.createElement('div'); modal.style.background='#fff'; modal.style.border='1px solid #e5e7eb'; modal.style.borderRadius='8px'; modal.style.maxWidth='520px'; modal.style.width='92%'; modal.style.margin='10% auto'; modal.style.padding='1rem';
        const title = document.createElement('h3'); title.textContent = `Redefinir senha do tenant ${t.tenant_id}`; title.style.marginTop='0';
        const form = document.createElement('div'); form.style.display='grid'; form.style.gridTemplateColumns='1fr'; form.style.gap='0.5rem';
        const inPw = document.createElement('input'); inPw.type='password'; inPw.placeholder='Nova senha (mín. 12 caracteres)';
        const inConfirm = document.createElement('input'); inConfirm.type='password'; inConfirm.placeholder='Confirmar nova senha';
        const actions = document.createElement('div'); actions.style.display='flex'; actions.style.justifyContent='flex-end'; actions.style.gap='0.5rem'; actions.style.marginTop='0.75rem';
        const btnCancel = document.createElement('button'); btnCancel.className='btn btn-secondary'; btnCancel.textContent='Cancelar'; btnCancel.onclick=()=>document.body.removeChild(overlay);
        const btnGenerate = document.createElement('button'); btnGenerate.className='btn btn-secondary'; btnGenerate.textContent='Gerar senha forte';
        btnGenerate.onclick = () => {
            // gera 16 chars com classes variadas
            const chars = {
                upper: 'ABCDEFGHJKLMNPQRSTUVWXYZ',
                lower: 'abcdefghijkmnopqrstuvwxyz',
                nums: '23456789',
                sym: '!@#$%^&*()-_=+[]{}?'
            };
            function pick(str, n){ let out=''; for(let i=0;i<n;i++){ out += str[Math.floor(Math.random()*str.length)]; } return out; }
            const candidate = pick(chars.upper,4)+pick(chars.lower,6)+pick(chars.nums,3)+pick(chars.sym,3);
            // embaralhar
            const arr = candidate.split(''); for(let i=arr.length-1;i>0;i--){ const j=Math.floor(Math.random()*(i+1)); [arr[i],arr[j]]=[arr[j],arr[i]]; }
            const pw = arr.join(''); inPw.value = pw; inConfirm.value = pw;
        };
        const btnSubmit = document.createElement('button'); btnSubmit.className='btn'; btnSubmit.textContent='Redefinir';
        btnSubmit.onclick = async () => {
            const pw = (inPw.value||'').trim(); const cf = (inConfirm.value||'').trim();
            if (!pw || pw.length < 12) { showError('Senha muito curta (mínimo 12)'); return; }
            if (pw !== cf) { showError('As senhas não coincidem'); return; }
            btnSubmit.disabled=true; const old=btnSubmit.textContent; btnSubmit.textContent='Redefinindo...';
            try {
                const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(t.tenant_id)}/reset-admin-password`, {
                    method:'POST',
                    body: JSON.stringify({ new_password: pw })
                });
                if (!resp) return; const json = await resp.json(); setResult(json);
                if (resp.ok) { showSuccess(`Senha redefinida. Nova senha: ${json.new_password}`); document.body.removeChild(overlay); }
                else { showError(json.error || 'Falha ao redefinir senha'); }
            } catch (e) { showError('Erro ao redefinir senha'); }
            finally { btnSubmit.disabled=false; btnSubmit.textContent=old; }
        };
        form.appendChild(inPw); form.appendChild(inConfirm);
        actions.appendChild(btnCancel); actions.appendChild(btnGenerate); actions.appendChild(btnSubmit);
        modal.appendChild(title); modal.appendChild(form); modal.appendChild(actions); overlay.appendChild(modal); document.body.appendChild(overlay);
    }

    async function toggleAccess(tenantId, enabled) {
        try {
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(tenantId)}/access`, {
                method: 'POST',
                body: JSON.stringify({ enabled })
            });
            if (!resp) return; const json = await resp.json(); setResult(json);
            if (resp.ok) { showSuccess(enabled ? 'Acesso liberado' : 'Acesso bloqueado'); refreshTenants(); } else { showError(json.error || 'Falha ao alterar acesso'); }
        } catch (e) { showError('Erro ao alterar acesso'); }
    }

    async function showPayments(tenantId) {
        try {
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(tenantId)}/payments`);
            if (!resp) return; const json = await resp.json();
            if (resp.ok) { setResult(json.data || []); showSuccess('Pagamentos carregados'); }
            else { showError(json.error || 'Falha ao listar pagamentos'); }
        } catch (e) { showError('Erro ao listar pagamentos'); }
    }

    function openEditTenantModal(t) {
        const overlay = document.createElement('div'); overlay.style.position='fixed'; overlay.style.inset='0'; overlay.style.background='rgba(0,0,0,0.35)'; overlay.style.zIndex='1000';
        const modal = document.createElement('div'); modal.style.background='#fff'; modal.style.border='1px solid #e5e7eb'; modal.style.borderRadius='8px'; modal.style.maxWidth='900px'; modal.style.width='95%'; modal.style.margin='3% auto'; modal.style.padding='1rem';
        const title = document.createElement('h3'); title.textContent = `Editar tenant ${t.tenant_id}`; title.style.marginTop='0';
        const form = document.createElement('div'); form.style.display='grid'; form.style.gridTemplateColumns='repeat(auto-fit,minmax(220px,1fr))'; form.style.gap='0.5rem';

        const inRazao = document.createElement('input'); inRazao.type='text'; inRazao.value = t.razao_social||''; inRazao.placeholder='Razão Social';
        const inName = document.createElement('input'); inName.type='text'; inName.value = t.name||''; inName.placeholder='Nome fantasia';
        const selTipo = document.createElement('select'); selTipo.innerHTML = '<option value="">Tipo: PF/PJ</option><option value="PF">PF</option><option value="PJ">PJ</option>'; selTipo.value = t.tipo||'';
        const inCPF = document.createElement('input'); inCPF.type='text'; inCPF.value = t.cpf||''; inCPF.placeholder='CPF';
        const inCNPJ = document.createElement('input'); inCNPJ.type='text'; inCNPJ.value = t.cnpj||''; inCNPJ.placeholder='CNPJ';
        const inIE = document.createElement('input'); inIE.type='text'; inIE.value = t.ie||''; inIE.placeholder='Inscrição Estadual';
        const inEmail = document.createElement('input'); inEmail.type='email'; inEmail.value = t.contact_email||''; inEmail.placeholder='Email de contato (opcional)';
        const selPlan = document.createElement('select');
        const optNone = document.createElement('option'); optNone.value=''; optNone.textContent='Plano: nenhum'; selPlan.appendChild(optNone);
        for (const p of cachedPlans) { const opt=document.createElement('option'); opt.value=String(p.id); opt.textContent=p.name; if (t.plan?.id===p.id) opt.selected=true; selPlan.appendChild(opt); }
        const inDomain = document.createElement('input'); inDomain.type='text'; inDomain.value = t.domain||''; inDomain.placeholder='Domínio (opcional)';
        const inCEP = document.createElement('input'); inCEP.type='text'; inCEP.value = (t.cep||t.endereco?.cep||''); inCEP.placeholder='CEP';
        const selTipoLog = document.createElement('select'); selTipoLog.innerHTML = '<option value="">Tipo de logradouro</option><option>Rua</option><option>Avenida</option><option>Travessa</option><option>Viela</option><option>Alameda</option><option>Estrada</option><option>Rodovia</option><option>Praça</option><option>Largo</option>'; selTipoLog.value = (t.logradouro_tipo||t.endereco?.tipo||'');
        const inLogradouro = document.createElement('input'); inLogradouro.type='text'; inLogradouro.value = (t.logradouro||t.endereco?.logradouro||''); inLogradouro.placeholder='Nome do logradouro';
        const inNumero = document.createElement('input'); inNumero.type='text'; inNumero.value = (t.numero||t.endereco?.numero||''); inNumero.placeholder='Número';
        const inComplemento = document.createElement('input'); inComplemento.type='text'; inComplemento.value = (t.complemento||t.endereco?.complemento||''); inComplemento.placeholder='Complemento';
        const inBairro = document.createElement('input'); inBairro.type='text'; inBairro.value = (t.bairro||t.endereco?.bairro||''); inBairro.placeholder='Bairro';
        const inCidade = document.createElement('input'); inCidade.type='text'; inCidade.value = (t.cidade||t.endereco?.cidade||''); inCidade.placeholder='Cidade';
        const inEstado = document.createElement('input'); inEstado.type='text'; inEstado.value = (t.estado||t.endereco?.estado||''); inEstado.placeholder='UF'; inEstado.maxLength = 2;

        [inRazao,inName,selTipo,inCPF,inCNPJ,inIE,inEmail,selPlan,inDomain,inCEP,selTipoLog,inLogradouro,inNumero,inComplemento,inBairro,inCidade,inEstado].forEach(el=>form.appendChild(el));

        const actions = document.createElement('div'); actions.style.display='flex'; actions.style.justifyContent='flex-end'; actions.style.gap='0.5rem'; actions.style.marginTop='0.75rem';
        const btnCancel = document.createElement('button'); btnCancel.className='btn btn-secondary'; btnCancel.textContent='Cancelar'; btnCancel.onclick=()=>document.body.removeChild(overlay);
        const btnSave = document.createElement('button'); btnSave.className='btn'; btnSave.textContent='Salvar';
        btnSave.onclick = async () => {
            const razao_social = (inRazao.value||'').trim(); if (!razao_social || razao_social.length < 5 || razao_social.length > 100) { showError('Razão Social é obrigatória (5 a 100 caracteres)'); return; }
            const name = (inName.value||'').trim(); if (!name || name.length < 2) { showError('Nome inválido'); return; }
            const email = (inEmail.value||'').trim(); if (email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { showError('Email inválido'); return; }
            const domain = (inDomain.value||'').trim(); if (domain && !/^[a-z0-9][a-z0-9\-\.]*\.[a-z]{2,}$/i.test(domain)) { showError('Domínio inválido'); return; }
            const tipo = (selTipo.value||'').trim(); const cpf = String(inCPF.value||'').replace(/\D+/g,''); const cnpj = String(inCNPJ.value||'').replace(/\D+/g,'');
            if (tipo && !['PF','PJ'].includes(tipo)) { showError('Tipo inválido: PF ou PJ'); return; }
            if (tipo === 'PF' && cnpj) { showError('PF não deve informar CNPJ'); return; }
            if (tipo === 'PJ' && cpf) { showError('PJ não deve informar CPF'); return; }
            if (cpf && cpf.length !== 11) { showError('CPF inválido'); return; }
            if (cnpj && cnpj.length !== 14) { showError('CNPJ inválido'); return; }
            const ie = String(inIE.value||'').replace(/\D+/g,''); if (ie && ie.length !== 9) { showError('Inscrição Estadual inválida'); return; }
            const cep = String(inCEP.value||'').replace(/\D+/g,''); if (cep && !/^\d{8}$/.test(cep)) { showError('CEP inválido'); return; }
            const estado = (inEstado.value||'').trim().toUpperCase(); if (estado && !/^([A-Z]{2})$/.test(estado)) { showError('UF inválida'); return; }
            const body = {
                razao_social,
                name,
                contact_email: email,
                domain,
                tipo,
                cpf,
                cnpj,
                ie,
                cep,
                logradouro_tipo: (selTipoLog.value||'').trim(),
                logradouro: (inLogradouro.value||'').trim(),
                numero: (inNumero.value||'').trim(),
                complemento: (inComplemento.value||'').trim(),
                bairro: (inBairro.value||'').trim(),
                cidade: (inCidade.value||'').trim(),
                estado,
                plan_id: selPlan.value || null
            };
            btnSave.disabled = true; const oldText = btnSave.textContent; btnSave.textContent = 'Salvando...';
            try {
                const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(t.tenant_id)}`, { method:'PUT', body: JSON.stringify(body) });
                if (!resp) return; const json = await resp.json(); setResult(json);
                if (resp.ok) { showSuccess('Tenant atualizado'); document.body.removeChild(overlay); refreshTenants(); }
                else { showError(json.error || 'Falha ao atualizar'); }
            } catch (e) { showError('Erro ao atualizar tenant'); }
            finally { btnSave.disabled=false; btnSave.textContent=oldText; }
        };
        actions.appendChild(btnCancel); actions.appendChild(btnSave);
        modal.appendChild(title); modal.appendChild(form); modal.appendChild(actions); overlay.appendChild(modal); document.body.appendChild(overlay);
    }

    function openTenantSummary(t) {
        const overlay = document.createElement('div'); overlay.style.position='fixed'; overlay.style.inset='0'; overlay.style.background='rgba(0,0,0,0.35)'; overlay.style.zIndex='1000';
        const modal = document.createElement('div'); modal.style.background='#fff'; modal.style.border='1px solid #e5e7eb'; modal.style.borderRadius='8px'; modal.style.maxWidth='600px'; modal.style.width='92%'; modal.style.margin='5% auto'; modal.style.padding='1rem';
        const title = document.createElement('h3'); title.textContent = `Resumo do tenant ${t.tenant_id}`; title.style.marginTop='0';
        const addrTipo = (t.logradouro_tipo || (t.endereco?.tipo) || '');
        const addrNome = (t.logradouro || (t.endereco?.logradouro) || '');
        const addrNumero = (t.numero || (t.endereco?.numero) || '');
        const addrLine = [addrTipo, addrNome, addrNumero].filter(Boolean).join(' ');
        const info = document.createElement('div');
        info.innerHTML = `
            <div><strong>Razão Social:</strong> ${t.razao_social||'-'}</div>
            <div><strong>Nome:</strong> ${t.name||'-'}</div>
            <div><strong>Email:</strong> ${t.contact_email||'-'}</div>
            <div><strong>Domínio:</strong> ${t.domain||'-'}</div>
            <div><strong>Endereço:</strong> ${addrLine||'-'}</div>
            <div><strong>Cidade/UF:</strong> ${((t.cidade||t.endereco?.cidade||'-')+'/'+(t.estado||t.endereco?.estado||'-'))}</div>
            <div><strong>CEP:</strong> ${(t.cep||t.endereco?.cep||'-')}</div>
            <div><strong>Tipo:</strong> ${t.tipo||'-'}</div>
            <div><strong>CPF/CNPJ:</strong> ${t.tipo==='PF' ? (t.cpf||'-') : (t.cnpj||'-')}</div>
            <div><strong>Inscrição Estadual:</strong> ${t.ie||'-'}</div>
            <div><strong>Plano:</strong> ${t.plan?.name||'-'}</div>
        `;
        const actions = document.createElement('div'); actions.style.display='flex'; actions.style.justifyContent='flex-end'; actions.style.gap='0.5rem'; actions.style.marginTop='0.75rem';
        const btnClose = document.createElement('button'); btnClose.className='btn'; btnClose.textContent='Fechar'; btnClose.onclick=()=>document.body.removeChild(overlay);
        actions.appendChild(btnClose);
        modal.appendChild(title); modal.appendChild(info); modal.appendChild(actions); overlay.appendChild(modal); document.body.appendChild(overlay);
    }

    function confirmDeleteTenant(tenantId) {
        const overlay = document.createElement('div'); overlay.style.position='fixed'; overlay.style.inset='0'; overlay.style.background='rgba(0,0,0,0.35)'; overlay.style.zIndex='1000';
        const modal = document.createElement('div'); modal.style.background='#fff'; modal.style.border='1px solid #e5e7eb'; modal.style.borderRadius='8px'; modal.style.maxWidth='520px'; modal.style.width='92%'; modal.style.margin='10% auto'; modal.style.padding='1rem';
        const msg = document.createElement('p'); msg.textContent = 'Tem certeza que deseja excluir este tenant?';
        const actions = document.createElement('div'); actions.style.display='flex'; actions.style.justifyContent='flex-end'; actions.style.gap='0.5rem';
        const btnCancel = document.createElement('button'); btnCancel.className='btn btn-secondary'; btnCancel.textContent='Cancelar'; btnCancel.onclick=()=>document.body.removeChild(overlay);
        const btnConfirm = document.createElement('button'); btnConfirm.className='btn btn-danger'; btnConfirm.textContent='Confirmar';
        btnConfirm.onclick = async () => {
            btnConfirm.disabled=true; const old=btnConfirm.textContent; btnConfirm.textContent='Excluindo...';
            try {
                const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(tenantId)}`, { method:'DELETE' });
                if (!resp) return; const json = await resp.json(); setResult(json);
                if (resp.ok) { showSuccess('Tenant removido'); document.body.removeChild(overlay); refreshTenants(); }
                else { showError(json.error || 'Falha ao remover'); }
            } catch (e) { showError('Erro ao remover tenant'); }
            finally { btnConfirm.disabled=false; btnConfirm.textContent=old; }
        };
        actions.appendChild(btnCancel); actions.appendChild(btnConfirm);
        modal.appendChild(msg); modal.appendChild(actions); overlay.appendChild(modal); document.body.appendChild(overlay);
    }

    document.addEventListener('DOMContentLoaded', () => {
        document.getElementById('refreshBtn').addEventListener('click', refreshTenants);
        const printTenantsBtn = document.getElementById('printTenantsBtn');
        if (printTenantsBtn) printTenantsBtn.addEventListener('click', () => printTableById('tenantsTable', 'Lista de Tenants'));
        document.getElementById('searchInput').addEventListener('input', renderTenants);
        document.getElementById('statusFilter').addEventListener('change', renderTenants);
        document.getElementById('planFilter').addEventListener('change', renderTenants);
        const df = document.getElementById('domainFilter'); if (df) df.addEventListener('input', renderTenants);
        const dF = document.getElementById('dateFrom'); if (dF) dF.addEventListener('change', renderTenants);
        const dT = document.getElementById('dateTo'); if (dT) dT.addEventListener('change', renderTenants);
        document.getElementById('createBtn').addEventListener('click', createTenant);
        // botão de sair já está presente no header; nenhum handler local aqui
        document.querySelectorAll('.tab-btn').forEach(btn => btn.addEventListener('click', () => switchTab(btn.getAttribute('data-tab'))));

        // Máscaras e auto-preenchimento (CPF/CNPJ/CEP)
        const tipo = document.getElementById('newTenantTipo');
        const razao = document.getElementById('newTenantRazaoSocial');
        const ie = document.getElementById('newTenantIE');
        const cpf = document.getElementById('newTenantCpf');
        const cnpj = document.getElementById('newTenantCnpj');
        const cep = document.getElementById('newTenantCep');
        const nome = document.getElementById('newTenantName');
        const tipoLogradouro = document.getElementById('newTenantTipoLogradouro');
        const logradouro = document.getElementById('newTenantLogradouro');
        const numeroField = document.getElementById('newTenantNumero');
        const complementoField = document.getElementById('newTenantComplemento');
        const bairro = document.getElementById('newTenantBairro');
        const cidade = document.getElementById('newTenantCidade');
        const estado = document.getElementById('newTenantEstado');
        const emailField = document.getElementById('newTenantEmail');

        function digits(s){ return String(s||'').replace(/\D+/g,''); }
        function maskCPF(v){ const d = digits(v).slice(0,11); return d.replace(/(\d{3})(\d)/,'$1.$2').replace(/(\d{3})(\d)/,'$1.$2').replace(/(\d{3})(\d{1,2})$/,'$1-$2'); }
        function maskCNPJ(v){ const d = digits(v).slice(0,14); return d.replace(/(\d{2})(\d)/,'$1.$2').replace(/(\d{3})(\d)/,'$1.$2').replace(/(\d{3})(\d)/,'$1/$2').replace(/(\d{4})(\d{1,2})$/,'$1-$2'); }
        function maskCEP(v){ const d = digits(v).slice(0,8); return d.replace(/(\d{5})(\d{1,3})$/,'$1-$2'); }
        function maskIE(v){ const d = digits(v).slice(0,9); return d.replace(/(\d{2})(\d)/,'$1.$2').replace(/(\d{3})(\d)/,'$1.$2').replace(/(\d{3})(\d{1})$/,'$1-$2'); }

        if (ie) ie.addEventListener('input', () => { ie.value = maskIE(ie.value); });
        if (razao) razao.addEventListener('blur', () => {
            const v = (razao.value||'').trim();
            if (v.length < 5) showError('Razão Social: mínimo 5 caracteres');
        });

        if (tipo) tipo.addEventListener('change', () => {
            const val = tipo.value;
            if (val === 'PF') { if (cpf) cpf.disabled = false; if (cnpj) { cnpj.disabled = true; cnpj.value=''; } }
            else if (val === 'PJ') { if (cnpj) cnpj.disabled = false; if (cpf) { cpf.disabled = true; cpf.value=''; } }
            else { if (cpf) { cpf.disabled = false; } if (cnpj) { cnpj.disabled = false; } }
        });
        if (cpf) cpf.addEventListener('input', () => { cpf.value = maskCPF(cpf.value); });
        if (cnpj) {
            cnpj.addEventListener('input', () => { cnpj.value = maskCNPJ(cnpj.value); });
            cnpj.addEventListener('blur', async () => {
                const d = digits(cnpj.value);
                if (d.length !== 14) return;
                try {
                    const resp = await fetch(`https://brasilapi.com.br/api/cnpj/v1/${d}`);
                    if (!resp.ok) return;
                    const j = await resp.json();
                    if (razao && (!razao.value || razao.value.trim()==='')) razao.value = j.razao_social || razao.value;
                    if (nome && (!nome.value || nome.value.trim()==='')) nome.value = j.nome_fantasia || j.razao_social || nome.value;
                    if (j.logradouro){
                        const parts = splitLogradouroParts(j.logradouro);
                        if (tipoLogradouro && (!tipoLogradouro.value || tipoLogradouro.value.trim()==='') && parts.tipo) tipoLogradouro.value = parts.tipo;
                        if (logradouro && (!logradouro.value || logradouro.value.trim()==='')) logradouro.value = parts.nome || logradouro.value;
                    }
                    if (numeroField && (!numeroField.value || numeroField.value.trim()==='')) numeroField.value = j.numero || numeroField.value;
                    if (complementoField && (!complementoField.value || complementoField.value.trim()==='')) complementoField.value = j.complemento || complementoField.value;
                    if (bairro && (!bairro.value || bairro.value.trim()==='')) bairro.value = j.bairro || bairro.value;
                    if (cidade && (!cidade.value || cidade.value.trim()==='')) cidade.value = j.municipio || cidade.value;
                    if (estado && (!estado.value || estado.value.trim()==='')) estado.value = j.uf || estado.value;
                    if (cep && (!cep.value || cep.value.trim()==='')) cep.value = j.cep ? maskCEP(j.cep) : cep.value;
                    if (emailField && (!emailField.value || emailField.value.trim()==='')) emailField.value = j.email || emailField.value;
                    showSuccess('Dados do CNPJ preenchidos automaticamente');
                } catch (_) { /* silencioso */ }
            });
        }
        if (cep) {
            cep.addEventListener('input', () => { cep.value = maskCEP(cep.value); });
            cep.addEventListener('blur', async () => {
                const d = digits(cep.value);
                if (d.length !== 8) return;
                try {
                    const resp = await fetch(`https://viacep.com.br/ws/${d}/json/`);
                    if (!resp.ok) return; const j = await resp.json(); if (j.erro) return;
                    if (j.logradouro){
                        const parts = splitLogradouroParts(j.logradouro);
                        if (tipoLogradouro && (!tipoLogradouro.value || tipoLogradouro.value.trim()==='') && parts.tipo) tipoLogradouro.value = parts.tipo;
                        if (logradouro && (!logradouro.value || logradouro.value.trim()==='')) logradouro.value = parts.nome || logradouro.value;
                    }
                    if (bairro && (!bairro.value || bairro.value.trim()==='')) bairro.value = j.bairro || bairro.value;
                    if (cidade && (!cidade.value || cidade.value.trim()==='')) cidade.value = j.localidade || cidade.value;
                    if (estado && (!estado.value || estado.value.trim()==='')) estado.value = j.uf || estado.value;
                    showSuccess('Endereço preenchido pelo CEP');
                } catch (_) {}
            });
            // Autocomplete de logradouro usando ViaCEP (precisa cidade e estado)
            if (logradouro) {
                let lograTimer;
                logradouro.addEventListener('input', () => {
                    clearTimeout(lograTimer);
                    const q = (logradouro.value||'').trim();
                    const uf = (estado.value||'').trim();
                    const city = (cidade.value||'').trim();
                    if (q.length < 3 || !uf || !city) return;
                    lograTimer = setTimeout(async () => {
                        try {
                            const resp = await fetch(`https://viacep.com.br/ws/${encodeURIComponent(uf)}/${encodeURIComponent(city)}/${encodeURIComponent(q)}/json/`);
                            if (!resp.ok) return; const arr = await resp.json();
                            const dl = document.getElementById('logradouroList'); if (!dl) return;
                            dl.innerHTML = '';
                            (Array.isArray(arr)?arr:[]).slice(0,10).forEach(item => {
                                const parts = splitLogradouroParts(item.logradouro||'');
                                const opt = document.createElement('option'); opt.value = parts.nome || '';
                                dl.appendChild(opt);
                            });
                        } catch (_) {}
                    }, 300);
                });
            }
        }

        refreshTenants();
    });

    // ---- Dashboard rendering ----
    function renderDashboard() {
        const total = cachedTenants.length;
        const active = cachedTenants.filter(t => t.status === 'active').length;
        const suspended = cachedTenants.filter(t => t.status === 'suspended').length;
        const now = new Date();
        const ym = `${now.getFullYear()}-${String(now.getMonth()+1).padStart(2,'0')}`;
        let revenue = 0;
        for (const t of cachedTenants) {
            const lp = t.last_payment;
            if (lp && (lp.status||'').toLowerCase() === 'paid' && (lp.occurred_at||'').startsWith(ym)) {
                revenue += (lp.amount_cents||0)/100;
            }
        }
        const elTotal = document.getElementById('kpiTotal'); if (elTotal) elTotal.textContent = String(total);
        const elActive = document.getElementById('kpiActive'); if (elActive) elActive.textContent = String(active);
        const elSusp = document.getElementById('kpiSuspended'); if (elSusp) elSusp.textContent = String(suspended);
        const elRev = document.getElementById('kpiRevenue'); if (elRev) elRev.textContent = formatBRL(revenue);
        const alerts = document.getElementById('alerts');
        if (alerts) {
            alerts.innerHTML = '';
            if (suspended > 0) { const li = document.createElement('li'); li.textContent = `${suspended} tenants suspensos.`; alerts.appendChild(li); }
            const noPlan = cachedTenants.filter(t => !t.plan.id).length;
            if (noPlan > 0) { const li = document.createElement('li'); li.textContent = `${noPlan} tenants sem plano.`; alerts.appendChild(li); }
            if (alerts.children.length === 0) { const li = document.createElement('li'); li.textContent = 'Sem alertas.'; alerts.appendChild(li); }
        }

        // Gráfico: Tenants por plano (barras simples)
        try {
            const plansCount = {};
            for (const t of cachedTenants) {
                const pname = t.plan?.name || 'Sem plano';
                plansCount[pname] = (plansCount[pname] || 0) + 1;
            }
            const labels = Object.keys(plansCount);
            const values = labels.map(l => plansCount[l]);
            const canvas = document.getElementById('chartPlans');
            if (canvas) {
                const ctx = canvas.getContext('2d');
                const W = canvas.width, H = canvas.height;
                ctx.clearRect(0,0,W,H);
                const max = Math.max(1, ...values);
                const mLeft = 40, mBottom = 30, mTop = 20, mRight = 20;
                const plotW = W - mLeft - mRight, plotH = H - mTop - mBottom;
                const barW = Math.max(20, Math.floor(plotW / (labels.length * 1.6)));
                ctx.fillStyle = '#111'; ctx.font = '12px Segoe UI';
                // axes
                ctx.beginPath(); ctx.moveTo(mLeft, mTop); ctx.lineTo(mLeft, H - mBottom); ctx.lineTo(W - mRight, H - mBottom); ctx.strokeStyle = '#ddd'; ctx.stroke();
                // bars
                let x = mLeft + 12;
                for (let i = 0; i < labels.length; i++) {
                    const v = values[i];
                    const h = Math.round((v / max) * (plotH - 10));
                    ctx.fillStyle = '#2563eb';
                    ctx.fillRect(x, (H - mBottom - h), barW, h);
                    ctx.fillStyle = '#333';
                    ctx.fillText(String(v), x + barW/2 - 6, (H - mBottom - h) - 6);
                    const lbl = String(labels[i]).slice(0,10);
                    ctx.save(); ctx.translate(x + barW/2, H - mBottom + 12); ctx.rotate(-Math.PI/6);
                    ctx.fillText(lbl, -lbl.length*3.2, 0); ctx.restore();
                    x += barW + 16;
                }
            }
        } catch (_) {}

        // Gráfico: Cadastros por mês (últimos 6 meses)
        try {
            const months = [];
            const nowD = new Date();
            for (let i = 5; i >= 0; i--) {
                const d = new Date(nowD.getFullYear(), nowD.getMonth() - i, 1);
                const key = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`;
                months.push(key);
            }
            const counts = months.reduce((acc,m)=>{acc[m]=0;return acc;},{});
            for (const t of cachedTenants) {
                const created = (t.created_at||'').slice(0,7);
                if (counts.hasOwnProperty(created)) counts[created]++;
            }
            const canvas2 = document.getElementById('chartSignups');
            if (canvas2) {
                const ctx = canvas2.getContext('2d');
                const W = canvas2.width, H = canvas2.height;
                ctx.clearRect(0,0,W,H);
                const vals = months.map(m => counts[m]);
                const max = Math.max(1, ...vals);
                const mLeft = 40, mBottom = 30, mTop = 20, mRight = 20;
                const plotW = W - mLeft - mRight, plotH = H - mTop - mBottom;
                ctx.beginPath(); ctx.moveTo(mLeft, mTop); ctx.lineTo(mLeft, H - mBottom); ctx.lineTo(W - mRight, H - mBottom); ctx.strokeStyle = '#ddd'; ctx.stroke();
                ctx.strokeStyle = '#10b981'; ctx.lineWidth = 2; ctx.beginPath();
                for (let i = 0; i < vals.length; i++) {
                    const x = mLeft + (i/(vals.length-1)) * plotW;
                    const y = (H - mBottom) - Math.round((vals[i]/max) * (plotH - 10));
                    if (i === 0) ctx.moveTo(x,y); else ctx.lineTo(x,y);
                }
                ctx.stroke();
                ctx.fillStyle = '#333'; ctx.font = '12px Segoe UI';
                for (let i = 0; i < months.length; i++) {
                    const x = mLeft + (i/(months.length-1)) * plotW;
                    const lbl = months[i].slice(5);
                    ctx.save(); ctx.translate(x, H - mBottom + 12); ctx.rotate(-Math.PI/6);
                    ctx.fillText(lbl, -8, 0); ctx.restore();
                }
            }
        } catch (_) {}
    }

    // ---- Financeiro ----
    function renderFinance() {
        const el = document.getElementById('financeSection'); if (!el) return;
        const wrap = document.createElement('div');
        // Formulário de registro de cobrança/pagamento
        const form = document.createElement('div');
        form.style.display='grid'; form.style.gridTemplateColumns='repeat(auto-fit,minmax(180px,1fr))'; form.style.gap='0.5rem'; form.style.marginBottom='0.75rem';
        form.innerHTML = `
            <select id="tenantPaymentSelect">
                ${cachedTenants.map(t => `<option value="${t.tenant_id}">${t.tenant_id} - ${t.name||''}</option>`).join('')}
            </select>
            <input id="paymentAmount" type="text" placeholder="Valor (R$)" />
            <input id="paymentDate" type="date" />
            <select id="paymentStatus">
                <option value="paid">Pago</option>
                <option value="pending">Pendente</option>
                <option value="failed">Falhou</option>
            </select>
            <input id="paymentProvider" type="text" placeholder="Gateway/Provedor" />
            <input id="paymentExternalId" type="text" placeholder="ID externo" />
            <input id="paymentNotes" type="text" placeholder="Observações" />
            <button id="registerPaymentBtn" class="btn">Registrar pagamento</button>
        `;
        wrap.appendChild(form);
        const table = document.createElement('table'); table.className = 'table';
        const thead = document.createElement('thead'); thead.innerHTML = '<tr><th>Tenant</th><th>Último Pagamento</th><th>Valor</th><th>Status</th><th>Ações</th></tr>';
        const tbody = document.createElement('tbody');
        for (const t of cachedTenants) {
            const tr = document.createElement('tr');
            const tdT = document.createElement('td'); tdT.textContent = t.tenant_id;
            const lp = t.last_payment;
            const tdDt = document.createElement('td'); tdDt.textContent = lp ? (lp.occurred_at || '-') : '-';
            const tdVal = document.createElement('td'); tdVal.textContent = lp ? formatBRL((lp.amount_cents||0)/100) : '-';
            const tdSt = document.createElement('td'); tdSt.textContent = lp ? (lp.status||'-') : '-';
            const tdAc = document.createElement('td');
            const btnList = document.createElement('button'); btnList.className='btn'; btnList.textContent='Ver histórico';
            btnList.addEventListener('click', () => showPayments(t.tenant_id));
            tdAc.appendChild(btnList);
            tr.appendChild(tdT); tr.appendChild(tdDt); tr.appendChild(tdVal); tr.appendChild(tdSt); tr.appendChild(tdAc);
            tbody.appendChild(tr);
        }
        table.appendChild(thead); table.appendChild(tbody); wrap.appendChild(table);
        el.innerHTML = ''; el.appendChild(wrap);
        const btn = document.getElementById('registerPaymentBtn'); if (btn) btn.onclick = registerPayment;
    }

    async function registerPayment() {
        try {
            const tenantId = (document.getElementById('tenantPaymentSelect').value||'').trim();
            const amountStr = document.getElementById('paymentAmount').value||'';
            const date = document.getElementById('paymentDate').value||'';
            const status = document.getElementById('paymentStatus').value||'paid';
            const provider = document.getElementById('paymentProvider').value||'';
            const external_id = document.getElementById('paymentExternalId').value||'';
            const notes = document.getElementById('paymentNotes').value||'';
            if (!tenantId) { showError('Selecione o tenant'); return; }
            const amount = parseBRL(amountStr);
            if (!amount || amount <= 0) { showError('Informe o valor'); return; }
            if (!date) { showError('Informe a data'); return; }
            const body = {
                amount_cents: Math.round(amount * 100),
                occurred_at: date,
                status,
                provider,
                external_id,
                notes
            };
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(tenantId)}/payments`, { method:'POST', body: JSON.stringify(body) });
            if (!resp) return; const json = await resp.json(); setResult(json);
            if (resp.ok) { showSuccess('Pagamento registrado'); refreshTenants(); }
            else { showError(json.error || 'Falha ao registrar pagamento'); }
        } catch (e) { showError('Erro ao registrar pagamento'); }
    }

    // ---- Módulos ----
    function renderModules() {
        const el = document.getElementById('modulesSection'); if (!el) return;
        const wrap = document.createElement('div');
        const msg = document.createElement('div');
        msg.className = 'muted';
        msg.textContent = 'Em breve: gestão de módulos opcionais por tenant/planos.';
        wrap.appendChild(msg);
        el.innerHTML = ''; el.appendChild(wrap);
    }

    async function showModules(tenantId) {
        try {
            const t = cachedTenants.find(x => x.tenant_id === tenantId);
            if (!t) { showError('Tenant não encontrado'); return; }
            // Buscar overrides atuais e lista de módulos disponíveis
            const [respOv, respMods] = await Promise.all([
                callAdminApi(`/api/admin/tenants/${encodeURIComponent(tenantId)}/modules`),
                apiRequest('/debug/modules-status')
            ]);
            if (!respOv || !respMods) return;
            const jsonOv = await respOv.json().catch(() => ({}));
            const jsonMods = await respMods.json().catch(() => []);
            const ovArr = (jsonOv && jsonOv.data && Array.isArray(jsonOv.data)) ? jsonOv.data : [];
            const overrides = {};
            for (const o of ovArr) { overrides[String(o.module)] = !!o.enabled; }

            // Extrair nomes dos módulos a partir de class ou file
            const availableRaw = Array.isArray(jsonMods) ? jsonMods : [];
            let available = availableRaw.map(it => {
                const cls = String(it.class||'');
                if (cls && cls.startsWith('Modules\\')) {
                    const mid = cls.replace(/^Modules\\/, '').replace(/\\Module$/, '');
                    return mid;
                }
                const file = String(it.file||'');
                const m = file.match(/[\\\/](modules|Modules)[\\\/]([^\\\/]+)[\\\/]/);
                return m ? m[2] : '';
            }).filter(Boolean);
            // Remover duplicados e módulos não configuráveis
            const skip = new Set(['Admin', 'Auth']);
            available = Array.from(new Set(available)).filter(n => !skip.has(n));
            available.sort((a,b) => a.localeCompare(b));

            // Módulos padrão do plano
            const planMods = t.plan?.modules || {};
            const effective = {};
            for (const name of available) {
                if (Object.prototype.hasOwnProperty.call(overrides, name)) effective[name] = !!overrides[name];
                else if (Object.prototype.hasOwnProperty.call(planMods, name)) effective[name] = !!planMods[name];
                else effective[name] = false;
            }

            // Construir modal simples
            const overlay = document.createElement('div');
            overlay.style.position = 'fixed'; overlay.style.inset = '0'; overlay.style.background = 'rgba(0,0,0,0.35)'; overlay.style.zIndex = '1000';
            const modal = document.createElement('div');
            modal.style.background = '#fff'; modal.style.border = '1px solid #e5e7eb'; modal.style.borderRadius = '8px';
            modal.style.maxWidth = '640px'; modal.style.width = '90%'; modal.style.margin = '5% auto'; modal.style.padding = '1rem';
            const title = document.createElement('h3'); title.textContent = `Módulos do tenant ${tenantId}`; title.style.marginTop='0';
            const desc = document.createElement('div'); desc.className='muted'; desc.textContent = 'Marque os módulos habilitados para este tenant. Overrides substituem o padrão do plano.';
            const list = document.createElement('div'); list.style.display='grid'; list.style.gridTemplateColumns='repeat(auto-fit,minmax(180px,1fr))'; list.style.gap='0.5rem'; list.style.margin='0.75rem 0';
            for (const name of available) {
                const label = document.createElement('label'); label.style.display='flex'; label.style.alignItems='center'; label.style.gap='0.5rem'; label.style.border='1px solid #e5e7eb'; label.style.padding='0.5rem'; label.style.borderRadius='6px';
                const cb = document.createElement('input'); cb.type='checkbox'; cb.checked = !!effective[name]; cb.dataset.module = name;
                const span = document.createElement('span'); span.textContent = name;
                label.appendChild(cb); label.appendChild(span);
                list.appendChild(label);
            }
            const actions = document.createElement('div'); actions.style.display='flex'; actions.style.justifyContent='flex-end'; actions.style.gap='0.5rem';
            const btnCancel = document.createElement('button'); btnCancel.className='btn btn-secondary'; btnCancel.textContent='Cancelar';
            btnCancel.addEventListener('click', () => { document.body.removeChild(overlay); });
            const btnSave = document.createElement('button'); btnSave.className='btn'; btnSave.textContent='Salvar';
            btnSave.addEventListener('click', async () => {
                try {
                    const inputs = list.querySelectorAll('input[type="checkbox"][data-module]');
                    const mods = {};
                    inputs.forEach(i => { mods[String(i.dataset.module)] = !!i.checked; });
                    const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(tenantId)}/modules`, { method: 'POST', body: JSON.stringify({ modules: mods }) });
                    if (!resp) return; const json = await resp.json(); setResult(json);
                    if (resp.ok) { showSuccess('Módulos atualizados'); document.body.removeChild(overlay); refreshTenants(); }
                    else { showError(json.error || 'Falha ao salvar módulos'); }
                } catch (e) { showError('Erro ao salvar módulos'); }
            });
            actions.appendChild(btnCancel); actions.appendChild(btnSave);
            modal.appendChild(title);
            modal.appendChild(desc);
            modal.appendChild(list);
            // Info do plano
            const info = document.createElement('div'); info.className='muted';
            const enabledByPlan = Object.keys(planMods).filter(k => !!planMods[k]).sort().join(', ') || 'nenhum';
            info.textContent = `Plano padrão (${t.plan?.name||'-'}): ${enabledByPlan}`;
            info.style.marginBottom='0.5rem';
            modal.appendChild(info);
            modal.appendChild(actions);
            overlay.appendChild(modal);
            document.body.appendChild(overlay);
        } catch (e) {
            showError('Erro ao abrir configuração de módulos');
        }
    }

    // ---- Relatórios ----
    function renderReports() {
        const el = document.getElementById('reportsSection'); if (!el) return;
        const info = document.createElement('div'); info.className='muted'; info.textContent='Em breve: relatórios gerenciais com filtros e exportações.';
        const table = document.createElement('table'); table.className = 'table'; table.id = 'reportsTable';
        table.innerHTML = '<thead><tr><th>Tenant</th><th>Nome</th><th>Domínio</th><th>Status</th><th>Plano</th><th>Cadastro</th></tr></thead>';
        const tbody = document.createElement('tbody');
        for (const t of cachedTenants) {
            const tr = document.createElement('tr');
            tr.innerHTML = `<td>${t.tenant_id}</td><td>${t.name||'-'}</td><td>${t.domain||'-'}</td><td>${t.status}</td><td>${t.plan?.name||'-'}</td><td>${(t.created_at||'').replace('T',' ').replace('.000Z','')||'-'}</td>`;
            tbody.appendChild(tr);
        }
        table.appendChild(tbody);
        el.innerHTML = ''; el.appendChild(info); el.appendChild(table);
        const btn = document.getElementById('exportCsvBtn');
        if (btn) {
            btn.onclick = () => {
                const rows = [['Tenant','Nome','Domínio','Status','Plano','Cadastro']].concat(cachedTenants.map(t => [t.tenant_id, t.name||'', t.domain||'', t.status||'', t.plan?.name||'', (t.created_at||'')]));
                const csv = rows.map(r => r.map(v => '"'+String(v).replace(/"/g,'""')+'"').join(',')).join('\n');
                const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a'); a.href = url; a.download = 'tenants.csv'; a.click();
                URL.revokeObjectURL(url);
            };
        }
        const pbtn = document.getElementById('printReportsBtn');
        if (pbtn) {
            pbtn.onclick = () => printTableById('reportsTable', 'Relatório Gerencial');
        }
    }

    // ---- Planos (CRUD) ----
    function renderPlansList() {
        const container = document.getElementById('plansSection');
        if (!container) return; // painel não disponível
        // Sempre preencher o container existente para evitar estado vazio
        container.innerHTML = `
            <div style="display:flex;gap:0.5rem;margin-bottom:0.75rem;align-items:center;flex-wrap:wrap;">
                <input id="planName" type="text" placeholder="nome do plano" style="min-width:220px;" autocomplete="off" />
                <input id="planPrice" type="text" placeholder="R$ 0,00" style="min-width:180px;" autocomplete="off" />
                <select id="planCycle" style="min-width:160px;">
                    <option value="mensal">Mensal</option>
                    <option value="trimestral">Trimestral</option>
                    <option value="semestral">Semestral</option>
                    <option value="anual">Anual</option>
                </select>
                <label style="display:flex;align-items:center;gap:0.4rem;">
                    <input id="planActive" type="checkbox" checked /> Ativo
                </label>
                <button id="createPlanBtn" class="btn">Criar plano</button>
            </div>
            <div class="table-responsive">
                <table class="table" id="plansTable">
                    <thead>
                        <tr>
                            <th>Nome</th>
                            <th>Preço</th>
                            <th>Ciclo</th>
                            <th>Status</th>
                            <th style="width:360px;">Ações</th>
                        </tr>
                    </thead>
                    <tbody id="plansBody"></tbody>
                </table>
            </div>
            <div id="plansTestLog" style="display:none;margin-top:0.5rem;background:#f9fafb;border:1px solid #e5e7eb;border-radius:4px;padding:0.5rem;max-height:240px;overflow:auto;"></div>`;
        document.getElementById('createPlanBtn').addEventListener('click', createPlan);
        const tbody = document.getElementById('plansBody');
        tbody.innerHTML = '';
        for (const p of cachedPlans) {
            const tr = document.createElement('tr');
            const tdName = document.createElement('td'); tdName.textContent = p.name;
            const tdPrice = document.createElement('td'); tdPrice.textContent = formatBRL(typeof p.price_brl !== 'undefined' ? p.price_brl : (typeof p.price !== 'undefined' ? p.price : 0));
            const tdCycle = document.createElement('td'); tdCycle.textContent = cycleLabel(p.cycle);
            const tdActive = document.createElement('td'); const status = (p.deleted_at ? 'Excluído' : (p.active ? 'Ativo' : 'Inativo')); tdActive.textContent = status;
            const tdActions = document.createElement('td');
            tdActions.style.display = 'grid'; tdActions.style.gridTemplateColumns = 'repeat(auto-fit, minmax(120px, 1fr))'; tdActions.style.gap = '0.5rem';
            const btnView = document.createElement('button'); btnView.className = 'btn btn-secondary'; btnView.textContent = 'Detalhes'; btnView.addEventListener('click', () => viewPlanDetails(p));
            const btnEdit = document.createElement('button'); btnEdit.className = 'btn'; btnEdit.textContent = 'Editar';
            btnEdit.addEventListener('click', () => editPlan(p));
            const btnModules = document.createElement('button'); btnModules.className = 'btn'; btnModules.textContent = 'Módulos padrão';
            btnModules.addEventListener('click', () => editPlanModules(p));
            const btnDelete = document.createElement('button'); btnDelete.className = 'btn btn-danger'; btnDelete.textContent = (p.deleted_at ? 'Excluído' : 'Desativar');
            btnDelete.addEventListener('click', () => deletePlan(p));
            tdActions.appendChild(btnView);
            tdActions.appendChild(btnEdit);
            tdActions.appendChild(btnModules);
            if (p.deleted_at) {
                const btnRestore = document.createElement('button'); btnRestore.className = 'btn'; btnRestore.textContent = 'Restaurar'; btnRestore.addEventListener('click', () => restorePlan(p)); tdActions.appendChild(btnRestore);
                btnEdit.disabled = true; btnModules.disabled = true;
            }
            tdActions.appendChild(btnDelete);
            tr.appendChild(tdName); tr.appendChild(tdPrice); tr.appendChild(tdCycle); tr.appendChild(tdActive); tr.appendChild(tdActions);
            tbody.appendChild(tr);
        }
    }

    async function createPlan() {
        const name = (document.getElementById('planName').value || '').trim();
        const price = parseBRL(document.getElementById('planPrice').value || '');
        const cycle = (document.getElementById('planCycle').value || 'mensal');
        const active = !!document.getElementById('planActive').checked;
        if (!name) { showError('Informe o nome do plano'); return; }
        try {
            // enviar como price_brl para evitar ambiguidades
            const resp = await callAdminApi('/api/admin/plans', { method: 'POST', body: JSON.stringify({ name, price_brl: price, cycle }) });
            if (!resp) return; const json = await resp.json(); setResult(json);
            if (resp.ok) {
                // se precisa marcar ativo, atualizar
                const created = (json.data || json).id;
                if (active === false) {
                    await callAdminApi(`/api/admin/plans/${created}`, { method: 'PUT', body: JSON.stringify({ active: 0 }) });
                }
                showSuccess('Plano criado');
                document.getElementById('planName').value='';
                document.getElementById('planPrice').value='';
                document.getElementById('planCycle').value='mensal';
                document.getElementById('planActive').checked=true;
                refreshTenants(); // atualiza lista de planos e filtros
            } else { showError(json.error || 'Falha ao criar plano'); }
        } catch (e) { showError('Erro ao criar plano'); }
    }

    async function editPlan(p) {
        openEditPlanModal(p);
    }

    async function deletePlan(p) {
        if (p.deleted_at) { showError('Plano já está excluído.'); return; }
        if (!confirm(`Desativar/Excluir (soft-delete) o plano "${p.name}"?`)) return;
        try {
            const resp = await callAdminApi(`/api/admin/plans/${encodeURIComponent(p.id)}`, { method: 'DELETE' });
            if (!resp) return; const json = await resp.json(); setResult(json);
            if (resp.ok) { showSuccess('Plano marcado como excluído'); refreshPlans(); } else { showError(json.error || 'Falha ao excluir plano'); }
        } catch (e) { showError('Erro ao desativar plano'); }
    }

    function openEditPlanModal(plan) {
        const overlay = document.createElement('div'); overlay.style.position='fixed'; overlay.style.inset='0'; overlay.style.background='rgba(0,0,0,0.4)'; overlay.style.zIndex='9999';
        const modal = document.createElement('div'); modal.style.background='#fff'; modal.style.border='1px solid #e5e7eb'; modal.style.borderRadius='8px'; modal.style.padding='1rem'; modal.style.maxWidth='520px'; modal.style.width='92%'; modal.style.margin='6% auto';
        const title = document.createElement('h3'); title.textContent = `Editar plano: ${plan.name}`; title.style.margin='0 0 0.75rem 0';
        const form = document.createElement('div'); form.style.display='grid'; form.style.gridTemplateColumns='1fr'; form.style.gap='0.5rem';
        const nameField = document.createElement('input'); nameField.type='text'; nameField.placeholder='Nome do plano'; nameField.value=plan.name||'';
        const currentPrice = (typeof plan.price_brl !== 'undefined' ? plan.price_brl : (typeof plan.price !== 'undefined' ? plan.price : 0));
        const priceField = document.createElement('input'); priceField.type='text'; priceField.placeholder='R$ 0,00'; priceField.value=formatBRL(currentPrice);
        const cycleField = document.createElement('select'); cycleField.innerHTML = '<option value="mensal">Mensal</option><option value="trimestral">Trimestral</option><option value="semestral">Semestral</option><option value="anual">Anual</option>';
        cycleField.value = String(plan.cycle||'mensal');
        const activeRow = document.createElement('label'); activeRow.style.display='flex'; activeRow.style.alignItems='center'; activeRow.style.gap='0.5rem';
        const activeField = document.createElement('input'); activeField.type='checkbox'; activeField.checked = !!plan.active; activeRow.appendChild(activeField); activeRow.appendChild(document.createTextNode('Ativo'));
        form.appendChild(nameField); form.appendChild(priceField); form.appendChild(cycleField); form.appendChild(activeRow);
        const actions = document.createElement('div'); actions.style.display='flex'; actions.style.justifyContent='flex-end'; actions.style.gap='0.5rem'; actions.style.marginTop='0.75rem';
        const btnCancel = document.createElement('button'); btnCancel.className='btn btn-secondary'; btnCancel.textContent='Cancelar'; btnCancel.onclick=()=>document.body.removeChild(overlay);
        const btnSave = document.createElement('button'); btnSave.className='btn'; btnSave.textContent='Salvar'; btnSave.onclick = async () => {
            const name = (nameField.value||'').trim(); if (!name) { showError('Informe o nome do plano'); return; }
            const price = parseBRL(priceField.value||'');
            const cycle = String(cycleField.value||'mensal');
            const active = activeField.checked ? 1 : 0;
            try {
                // enviar como price_brl para consistência com o backend
                const resp = await callAdminApi(`/api/admin/plans/${encodeURIComponent(plan.id)}`, { method:'PUT', body: JSON.stringify({ name, price_brl: price, cycle, active }) });
                if (!resp) return; const json = await resp.json(); setResult(json);
                if (resp.ok) { showSuccess('Plano atualizado'); document.body.removeChild(overlay); refreshTenants(); }
                else { showError(json.error || 'Falha ao atualizar plano'); }
            } catch (e) { showError('Erro ao atualizar plano'); }
        };
        actions.appendChild(btnCancel); actions.appendChild(btnSave);
        modal.appendChild(title); modal.appendChild(form); modal.appendChild(actions);
        overlay.appendChild(modal); document.body.appendChild(overlay);
    }

    async function restorePlan(p) {
        if (!p.deleted_at) { showError('Plano não está excluído'); return; }
        if (!confirm(`Restaurar plano "${p.name}"?`)) return;
        try {
            const resp = await callAdminApi(`/api/admin/plans/${encodeURIComponent(p.id)}/restore`, { method: 'POST' });
            if (!resp) return; const json = await resp.json(); setResult(json);
            if (resp.ok) { showSuccess('Plano restaurado'); refreshPlans(); } else { showError(json.error || 'Falha ao restaurar plano'); }
        } catch (e) { showError('Erro ao restaurar plano'); }
    }

    async function editPlanModules(plan) {
        try {
            const respMods = await fetch('/debug/modules-status');
            const modsJson = await respMods.json();
            const loaded = modsJson.loaded || {};
            const allModules = Object.keys(loaded).filter(m => !['Admin','Auth'].includes(m));
            const defaults = (() => {
                if (plan.modules_json) {
                    try { const dec = JSON.parse(plan.modules_json); if (dec && typeof dec === 'object') return dec; } catch(_) {}
                }
                if (plan.modules && typeof plan.modules === 'object') return plan.modules;
                return {};
            })();

            const container = document.createElement('div');
            container.style.maxHeight = '360px';
            container.style.overflow = 'auto';
            container.style.padding = '0.5rem 0.25rem';
            for (const m of allModules) {
                const row = document.createElement('label');
                row.style.display = 'flex'; row.style.alignItems = 'center'; row.style.gap = '0.5rem'; row.style.padding = '0.25rem 0';
                const cb = document.createElement('input'); cb.type = 'checkbox'; cb.name = 'module'; cb.value = m; cb.checked = !!defaults[m];
                const span = document.createElement('span'); span.textContent = m;
                row.appendChild(cb); row.appendChild(span);
                container.appendChild(row);
            }

            const modal = document.createElement('div');
            modal.style.position = 'fixed'; modal.style.left = '0'; modal.style.top = '0'; modal.style.width = '100%'; modal.style.height = '100%'; modal.style.background = 'rgba(0,0,0,0.4)'; modal.style.display = 'flex'; modal.style.alignItems = 'center'; modal.style.justifyContent = 'center'; modal.style.zIndex = '9999';
            const box = document.createElement('div'); box.style.background = '#fff'; box.style.border = '1px solid #e5e7eb'; box.style.borderRadius = '8px'; box.style.padding = '1rem'; box.style.maxWidth = '520px'; box.style.width = '92%';
            const h3 = document.createElement('h3'); h3.textContent = `Módulos padrão do plano: ${plan.name}`; h3.style.margin = '0 0 0.5rem 0';
            const actionBar = document.createElement('div'); actionBar.style.display = 'flex'; actionBar.style.justifyContent = 'flex-end'; actionBar.style.gap = '0.5rem'; actionBar.style.marginTop = '0.75rem';
            const btnCancel = document.createElement('button'); btnCancel.className = 'btn btn-secondary'; btnCancel.textContent = 'Cancelar'; btnCancel.onclick = () => document.body.removeChild(modal);
            const btnSave = document.createElement('button'); btnSave.className = 'btn'; btnSave.textContent = 'Salvar'; btnSave.onclick = async () => {
                const selected = {};
                container.querySelectorAll('input[type="checkbox"][name="module"]').forEach(cb => { selected[cb.value] = cb.checked; });
                try {
                    const resp = await callAdminApi(`/api/admin/plans/${encodeURIComponent(plan.id)}`, { method: 'PUT', body: JSON.stringify({ modules: selected }) });
                    const json = await resp.json(); setResult(json);
                    if (resp.ok) { showSuccess('Módulos padrão atualizados'); document.body.removeChild(modal); refreshTenants(); } else { showError(json.error || 'Falha ao salvar módulos'); }
                } catch (e) { showError('Erro ao salvar módulos do plano'); }
            };
            actionBar.appendChild(btnCancel); actionBar.appendChild(btnSave);
            box.appendChild(h3); box.appendChild(container); box.appendChild(actionBar);
            modal.appendChild(box);
            document.body.appendChild(modal);
        } catch (e) {
            showError('Erro ao listar módulos para planos');
        }
    }

    async function runBootstrap(t) {
        try {
            const resp = await callAdminApi(`/api/admin/tenants/${encodeURIComponent(t)}/bootstrap?demo=true`, { method: 'POST' });
            if (!resp) return;
            const json = await resp.json(); setResult(json);
            if (resp.ok && json.ok) showSuccess('Bootstrap concluído'); else showError(json.error || 'Falha no bootstrap');
        } catch (e) { showError('Erro no bootstrap'); }
    }

    // Utilitários de preço e ciclo
    function formatBRL(value) {
        const num = typeof value === 'number' ? value : parseBRL(String(value||''));
        try {
            return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(isNaN(num)?0:num);
        } catch (_) {
            const fixed = (isNaN(num)?0:num).toFixed(2).replace('.', ',');
            return 'R$ ' + fixed;
        }
    }
    function parseBRL(str) {
        let s = String(str||'').trim();
        if (s === '') return 0;
        // Remover tudo que não seja dígito, ponto ou vírgula
        s = s.replace(/[^0-9.,-]/g, '');
        // Se tiver ponto e vírgula: ponto é milhar, vírgula é decimal
        if (s.includes('.') && s.includes(',')) {
            s = s.replace(/\./g, '').replace(',', '.');
        } else if (s.includes(',')) {
            // Só vírgula: tratar como decimal
            s = s.replace(',', '.');
        } // Só ponto: já está em decimal
        const n = parseFloat(s);
        return isNaN(n) ? 0 : n;
    }
    function cycleLabel(c) {
        const map = { mensal: 'Mensal', trimestral: 'Trimestral', semestral: 'Semestral', anual: 'Anual' };
        return map[String(c||'').toLowerCase()] || String(c||'');
    }

    // Atualização automática (polling) da lista de planos
    let plansPollTimer = null;
    async function refreshPlans() {
        try {
            const resp = await callAdminApi('/api/admin/plans');
            if (!resp) return; const json = await resp.json();
            cachedPlans = (json.data || []);
            renderPlansList();
        } catch (_) {}
    }

    // Utilitário de impressão simples de tabelas
    function printTableById(tableId, title) {
        const table = document.getElementById(tableId);
        if (!table) { showError('Tabela não encontrada para impressão'); return; }
        const win = window.open('', '_blank');
        if (!win) { showError('Pop-up bloqueado. Permita janelas para imprimir.'); return; }
        const css = 'table{width:100%;border-collapse:collapse}th,td{border:1px solid #ddd;padding:6px;text-align:left}body{font-family:Segoe UI,Arial,sans-serif;margin:16px}h1{font-size:18px;margin-bottom:12px}';
        win.document.write('<html><head><title>'+String(title||'Impressão')+'</title><style>'+css+'</style></head><body>');
        win.document.write('<h1>'+String(title||'')+'</h1>');
        win.document.write(table.outerHTML);
        win.document.write('</body></html>');
        win.document.close();
        try { PrintControl.safeWindowPrint(win, { copies: 1 }); } catch(_){ try { win.focus(); win.print(); win.close(); } catch(__){} }
    }
    function safeRefreshPlans() {
        const panel = document.getElementById('panel-plans');
        const isActive = panel && panel.classList.contains('active');
        const nameEl = document.getElementById('planName');
        const priceEl = document.getElementById('planPrice');
        const cycleEl = document.getElementById('planCycle');
        const editingFocused = [nameEl, priceEl, cycleEl].some(el => el && document.activeElement === el);
        const editingDirty = [nameEl, priceEl].some(el => el && String(el.value||'').trim() !== '');
        if (isActive && (editingFocused || editingDirty)) {
            // Evita apagar o que o usuário está digitando
            return;
        }
        refreshPlans();
    }
    function startPlansPolling() { if (!plansPollTimer) { plansPollTimer = setInterval(safeRefreshPlans, 5000); } }
    startPlansPolling();

    // Detalhes do plano
    function viewPlanDetails(plan) {
        const overlay = document.createElement('div'); overlay.style.position='fixed'; overlay.style.left='0'; overlay.style.top='0'; overlay.style.width='100%'; overlay.style.height='100%'; overlay.style.background='rgba(0,0,0,0.4)'; overlay.style.display='flex'; overlay.style.alignItems='center'; overlay.style.justifyContent='center'; overlay.style.zIndex='9999';
        const modal = document.createElement('div'); modal.style.background='#fff'; modal.style.border='1px solid #e5e7eb'; modal.style.borderRadius='8px'; modal.style.padding='1rem'; modal.style.maxWidth='560px'; modal.style.width='92%';
        const h3 = document.createElement('h3'); h3.textContent = `Plano: ${plan.name}`; h3.style.margin='0 0 0.5rem 0';
        const pre = document.createElement('pre'); pre.style.background='#f9fafb'; pre.style.border='1px solid #e5e7eb'; pre.style.borderRadius='6px'; pre.style.padding='0.5rem'; pre.style.maxHeight='320px'; pre.style.overflow='auto';
        const normalized = {
            id: plan.id,
            name: plan.name,
            price_brl: (typeof plan.price_brl !== 'undefined') ? plan.price_brl : (plan.price || 0),
            cycle: plan.cycle,
            active: !!plan.active,
            status: (plan.deleted_at ? 'Excluído' : (plan.active ? 'Ativo' : 'Inativo')),
            deleted_at: plan.deleted_at || null,
            created_at: plan.created_at || null,
            updated_at: plan.updated_at || null,
            modules: (() => { try { return plan.modules_json ? JSON.parse(plan.modules_json) : (plan.modules || {}); } catch(_) { return {}; } })(),
            limits: (() => { try { return plan.limits_json ? JSON.parse(plan.limits_json) : (plan.limits || {}); } catch(_) { return {}; } })()
        };
        pre.textContent = JSON.stringify(normalized, null, 2);
        const actions = document.createElement('div'); actions.style.display='flex'; actions.style.justifyContent='flex-end'; actions.style.gap='0.5rem'; actions.style.marginTop='0.5rem';
        const btnClose = document.createElement('button'); btnClose.className='btn btn-secondary'; btnClose.textContent='Fechar'; btnClose.onclick=() => document.body.removeChild(overlay);
        actions.appendChild(btnClose);
        modal.appendChild(h3); modal.appendChild(pre); modal.appendChild(actions);
        overlay.appendChild(modal); document.body.appendChild(overlay);
    }

    // Testes automatizados de Planos (CRUD e restauração)
    async function runPlansTests() {
        const logEl = document.getElementById('plansTestLog');
        logEl.style.display = 'block'; logEl.textContent = '';
        const log = (m) => { logEl.textContent += `\n${new Date().toLocaleTimeString()} - ${m}`; logEl.scrollTop = logEl.scrollHeight; };
        const rnd = Math.floor(Math.random()*100000);
        const name = `Plano Teste ${rnd}`;
        const price = 123.45;
        try {
            log('Criando plano...');
            let resp = await callAdminApi('/api/admin/plans', { method: 'POST', body: JSON.stringify({ name, price_brl: price, cycle: 'mensal' }) });
            if (!resp || !resp.ok) { const j = resp ? await resp.json().catch(()=>({})) : {}; throw new Error('Falha ao criar: ' + (j.error||'')); }
            const created = (await resp.json()).data.id;
            log(`Criado ID=${created}`);

            log('Atualizando plano...');
            resp = await callAdminApi(`/api/admin/plans/${created}`, { method: 'PUT', body: JSON.stringify({ price_brl: price + 10, active: 1 }) });
            if (!resp.ok) { const j = await resp.json().catch(()=>({})); throw new Error('Falha ao atualizar: ' + (j.error||'')); }
            log('Atualizado');

            await refreshPlans();
            const afterCreate = (cachedPlans || []).find(p => p.id === created);
            if (!afterCreate) throw new Error('Plano não encontrado após criação');
            log('Visível na listagem');

            log('Excluindo (soft-delete)...');
            resp = await callAdminApi(`/api/admin/plans/${created}`, { method: 'DELETE' });
            if (!resp.ok) { const j = await resp.json().catch(()=>({})); throw new Error('Falha ao excluir: ' + (j.error||'')); }
            await refreshPlans();
            const afterDelete = (cachedPlans || []).find(p => p.id === created);
            if (!afterDelete || !afterDelete.deleted_at) throw new Error('Soft-delete não refletiu');
            log('Exclusão refletida');

            log('Restaurando...');
            resp = await callAdminApi(`/api/admin/plans/${created}/restore`, { method: 'POST' });
            if (!resp.ok) { const j = await resp.json().catch(()=>({})); throw new Error('Falha ao restaurar: ' + (j.error||'')); }
            await refreshPlans();
            const afterRestore = (cachedPlans || []).find(p => p.id === created);
            if (!afterRestore || afterRestore.deleted_at) throw new Error('Restauração não refletiu');
            log('Restauração refletida');

            showSuccess('Testes de Planos concluídos com sucesso');
        } catch (e) {
            showError('Teste de Planos falhou: ' + (e.message || e));
            const msg = e && e.message ? e.message : String(e);
            log('ERRO: ' + msg);
        }
    }

    function splitLogradouroParts(v){
        const s = String(v||'').trim();
        if (!s) return { tipo:'', nome:'' };
        const known = [
            ['rua','Rua','R','R.'],
            ['avenida','Avenida','Av','Av.'],
            ['travessa','Travessa','Tv','Tv.'],
            ['viela','Viela'],
            ['alameda','Alameda'],
            ['estrada','Estrada'],
            ['rodovia','Rodovia'],
            ['praca','Praça','Praça'],
            ['largo','Largo']
        ];
        const firstWord = s.split(/\s+/)[0].replace(/[\.,]/g,'');
        const rest = s.slice(firstWord.length).trim();
        const lw = firstWord.toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu,'');
        for (const syns of known){
            if (syns.map(x=>x.toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu,'')).includes(lw)){
                return { tipo: syns[1], nome: rest || '' };
            }
        }
        return { tipo:'', nome:s };
    }
</script>