// ============================================
// CRIADOR DE MESAS — admin-only, preview ao vivo
// ============================================

const PRESETS_LS_KEY = 'mastershot.admin.tablePresets';

const DEFAULT_THEME = {
    name:         window.t('Nova mesa'),
    model:        'classic',      // 'classic' (gabinete+pernas) | 'pro' (pedestal)
    cushionStyle: 'straight',     // 'straight' | 'chamfered'
    railProfile:  'square',       // 'square' | 'rounded'
    bodyProfile:  'square',       // 'square' | 'rounded'
    railMaterial: 'wood',         // 'wood' | 'chrome' | 'brass' | 'matte-black' | 'gloss-black'
    feltWeave:    'worsted',      // 'worsted' | 'speed' | 'wool' (trama do tecido, edição AAA)
    felt:         '#1f5a3f',
    cushion:      '#236b48',
    woodDark:     '#3d2618',
    woodFrame:    '#4d3320',
    railTop:      '#2a1810',
    accent:       '#e8e4d8',      // sights/diamantes do trilho
    pocketLining: '#101010',      // boca/interior da caçapa
    // Perfil da tabela "Em grau" (metros) — espelha defaults de themes.js.
    cushionNoseH:    0.035,       // altura do nariz (rampa mais funda = menor)
    cushionUndercut: 0.035,       // recuo da borracha sob o nariz
};

const MODEL_OPTIONS = [
    { id: 'classic', name: window.t('Clássica') },
    { id: 'pro',     name: 'Pro Tournament' },
];
const WEAVE_OPTIONS = [
    { id: 'worsted', name: window.t('Lã penteada') },
    { id: 'speed',   name: window.t('Speed (fina)') },
    { id: 'wool',    name: window.t('Lã tradicional') },
];

// Paleta curada de madeiras (FALLBACK). A fonte ÚNICA agora é o bridge
// (window.MastershotTablePreview.palettes.wood ← WOOD_PALETTE de themes.js);
// estes arrays só valem se o editor abrir antes do bridge ESM carregar.
// Antes eram cópias à mão que já tinham divergido (ex.: nome do rail).
const WOOD_PRESETS = [
    { name: window.t('Mogno'),     woodDark: '#3d1f10', woodFrame: '#52311e', railTop: '#2a1408' },
    { name: window.t('Carvalho'),  woodDark: '#7a4f2a', woodFrame: '#8c5f36', railTop: '#5a3920' },
    { name: window.t('Nogueira'),  woodDark: '#3a2418', woodFrame: '#4d3120', railTop: '#2a1810' },
    { name: window.t('Cerejeira'), woodDark: '#5a2818', woodFrame: '#6e3622', railTop: '#3d1d10' },
    { name: window.t('Ébano'),     woodDark: '#0e0a08', woodFrame: '#1a1410', railTop: '#080604' },
    { name: 'Maple',        woodDark: '#c8a06a', woodFrame: '#d4ad77', railTop: '#a07e4a' },
    { name: window.t('Pau-rosa'),  woodDark: '#4a1a1a', woodFrame: '#5e2222', railTop: '#341010' },
    { name: window.t('Preto'),     woodDark: '#0a0a0a', woodFrame: '#141414', railTop: '#1a1a1a' },
];

// Paleta curada de feltros — duas linhas:
//  • "Vivos" são os defaults atuais (após boost de saturação geral).
//  • "Escuros" preservam as cores anteriores (bordeaux/verde-mata) pra
//    quem prefere atmosfera mais discreta. Clicar aplica felt + cushion.
const FELT_PRESETS = [
    // Vivos
    { name: window.t('Verde Vivo'),      felt: '#2a7a52', cushion: '#2e8a5c', tier: 'vivo' },
    { name: window.t('Vermelho Vivo'),   felt: '#a82a3e', cushion: '#b53246', tier: 'vivo' },
    { name: window.t('Esmeralda Vivo'),  felt: '#1a7a44', cushion: '#1e8a4e', tier: 'vivo' },
    { name: window.t('Azul Carom'),      felt: '#1a8fc4', cushion: '#17a0d4', tier: 'vivo' },
    { name: window.t('Carom3D Verde'),   felt: '#1f6a3f', cushion: '#256e44', tier: 'vivo' },

    { name: 'TV Blue',            felt: '#1d5db2', cushion: '#2264bc', tier: 'vivo' },
    { name: window.t('Laranja Sunset'),  felt: '#c4571d', cushion: '#d2641f', tier: 'vivo' },
    { name: window.t('Roxo Royal'),      felt: '#5a2a8a', cushion: '#643a96', tier: 'vivo' },
    { name: window.t('Rosa Choque'),     felt: '#c42a6e', cushion: '#d23a7c', tier: 'vivo' },
    { name: window.t('Grafite'),         felt: '#3a3f44', cushion: '#464c52', tier: 'vivo' },
    { name: window.t('Dourado Deserto'), felt: '#9a7a3a', cushion: '#a8884a', tier: 'vivo' },

    // Escuros (cores antigas preservadas)
    { name: window.t('Verde Mahogany'),  felt: '#1f5a3f', cushion: '#236b48', tier: 'escuro' },
    { name: 'Bordeaux',           felt: '#5a1f2e', cushion: '#6e2638', tier: 'escuro' },
    { name: window.t('Esmeralda Escuro'),felt: '#0f4a2a', cushion: '#135a36', tier: 'escuro' },
    { name: window.t('Meia-Noite'),      felt: '#1a2d5a', cushion: '#22386e', tier: 'escuro' },
    { name: 'Obsidian',           felt: '#0a0a0a', cushion: '#161616', tier: 'escuro' },
    { name: window.t('Vegas Marrom'),    felt: '#2a1a00', cushion: '#3a2400', tier: 'escuro' },
    { name: window.t('Marfim'),          felt: '#8a7a55', cushion: '#a08e64', tier: 'escuro' },
];

const RAIL_MATERIALS = [   // FALLBACK — fonte única é o bridge (ver abaixo)
    { id: 'wood',        name: window.t('Madeira'),   tint: '#8c5f36' },
    { id: 'chrome',      name: window.t('Cromado'),   tint: '#cccccc' },
    { id: 'brass',       name: window.t('Latão'),     tint: '#c8a050' },
    { id: 'matte-black', name: window.t('Preto fosco'), tint: '#181818' },
    { id: 'gloss-black', name: window.t('Preto piano'), tint: '#0c0c0e' },
];

// Fonte única das paletas: o bridge (themes.js). Cai pros arrays-fallback
// acima só se o editor renderizar antes do bridge ESM publicar.
const getWoodPalette   = () => window.MastershotTablePreview?.palettes?.wood          || WOOD_PRESETS;
const getRailMaterials = () => window.MastershotTablePreview?.palettes?.railMaterials || RAIL_MATERIALS;

function loadPresets() {
    try {
        const raw = localStorage.getItem(PRESETS_LS_KEY);
        if (!raw) return [];
        const arr = JSON.parse(raw);
        return Array.isArray(arr) ? arr : [];
    } catch { return []; }
}
function savePresets(list) {
    try { localStorage.setItem(PRESETS_LS_KEY, JSON.stringify(list)); }
    catch {}
}

// === Form widgets ===

// Campo de cor com DRAFT local: o texto digitado nunca é "comido". Enquanto
// o hex não fecha (#rgb ou #rrggbb) a borda fica vermelha e nada é aplicado;
// ao fechar, normaliza e aplica. Re-sincroniza quando value muda por fora
// (clicar numa paleta, carregar outra mesa). onBlur reverte ao último válido.
function ColorRow({ label, hint, value, onChange }) {
    const [draft, setDraft] = React.useState(value);
    const [invalid, setInvalid] = React.useState(false);
    React.useEffect(() => { setDraft(value); setInvalid(false); }, [value]);
    const normalize = (v) => {
        const norm = window.MastershotTablePreview?.themes?.normalizeHex;
        if (norm) return norm(v);
        const t = String(v).trim();
        return /^#[0-9a-fA-F]{6}$/.test(t) ? t.toLowerCase() : null;
    };
    const onType = (raw) => {
        setDraft(raw);
        const n = normalize(raw);
        if (n) { setInvalid(false); onChange(n); }
        else setInvalid(true);
    };
    return (
        <div className="te-row">
            <div className="te-row-text">
                <div className="te-row-label">{label}</div>
                <div className="te-row-hint">{hint}</div>
            </div>
            <div className="te-row-control">
                <input
                    type="color"
                    className="te-color-input"
                    value={value}
                    onChange={(e) => onChange(e.target.value)}
                />
                <input
                    type="text"
                    className={invalid ? "te-hex-input te-hex-invalid" : "te-hex-input"}
                    value={draft}
                    spellCheck={false}
                    onChange={(e) => onType(e.target.value)}
                    onBlur={() => { setDraft(value); setInvalid(false); }}
                />
            </div>
        </div>
    );
}

function CushionStyleRow({ value, onChange }) {
    return (
        <div className="te-row">
            <div className="te-row-text">
                <div className="te-row-label">{window.t("Estilo da Tabela")}</div>
                <div className="te-row-hint">{window.t("Aresta interna da cushion — reta (parede vertical) ou em grau (chanfrada estilo K-66).")}</div>
            </div>
            <div className="te-row-control" style={{ gap: 6 }}>
                <button
                    className={value === 'straight' ? "te-tab te-tab-on" : "te-tab"}
                    onClick={() => onChange('straight')}>{window.t("Reta")}</button>
                <button
                    className={value === 'chamfered' ? "te-tab te-tab-on" : "te-tab"}
                    onClick={() => onChange('chamfered')}>{window.t("Em grau")}</button>
            </div>
        </div>
    );
}

// Slider numérico em milímetros (tema guarda metros). Range + número
// lado a lado; o preview reconstrói a mesa ao vivo a cada mudança.
function MmSliderRow({ label, hint, value, min, max, step = 1, onChange }) {
    const mm = Math.round((Number(value) || 0) * 1000);
    const set = (v) => {
        const n = Math.max(min, Math.min(max, Number(v)));
        if (Number.isFinite(n)) onChange(n / 1000);
    };
    return (
        <div className="te-row">
            <div className="te-row-text">
                <div className="te-row-label">{label}</div>
                <div className="te-row-hint">{hint}</div>
            </div>
            <div className="te-row-control" style={{ gap: 8, alignItems: "center" }}>
                <input type="range" min={min} max={max} step={step} value={mm}
                    style={{ width: 110 }}
                    onChange={(e) => set(e.target.value)}/>
                <input type="number" className="te-hex-input" min={min} max={max} step={step}
                    style={{ width: 58 }} value={mm}
                    onChange={(e) => set(e.target.value)}/>
                <span style={{ fontSize: 11, color: "var(--ink-400)" }}>mm</span>
            </div>
        </div>
    );
}

function ToggleRow({ label, hint, value, options, onChange }) {
    return (
        <div className="te-row">
            <div className="te-row-text">
                <div className="te-row-label">{label}</div>
                <div className="te-row-hint">{hint}</div>
            </div>
            <div className="te-row-control" style={{ gap: 6, flexWrap: "wrap", justifyContent: "flex-end", maxWidth: 220 }}>
                {options.map(opt => (
                    <button key={opt.id}
                        className={value === opt.id ? "te-tab te-tab-on" : "te-tab"}
                        onClick={() => onChange(opt.id)}>
                        {opt.name}
                    </button>
                ))}
            </div>
        </div>
    );
}

// Slider genérico (valor cru, não-mm) com leitura ao lado — pra opacidade/escala.
function RangeRow({ label, hint, value, min, max, step, format, onChange }) {
    const v = Number(value);
    return (
        <div className="te-row">
            <div className="te-row-text">
                <div className="te-row-label">{label}</div>
                {hint && <div className="te-row-hint">{hint}</div>}
            </div>
            <div className="te-row-control" style={{ gap: 8, alignItems: "center" }}>
                <input type="range" min={min} max={max} step={step} value={v} style={{ width: 120 }}
                    onChange={(e) => onChange(Number(e.target.value))}/>
                <span style={{ fontSize: 11, color: "var(--ink-400)", width: 36, textAlign: "right" }}>
                    {format ? format(v) : v.toFixed(2)}
                </span>
            </div>
        </div>
    );
}

// Logo/marca no pano: caminho do arquivo + tamanho/opacidade. Sem arte = sem
// logo (campo vazio). Espelha o fluxo file-based dos avatares.
function DecalControls({ decal, onChange }) {
    const d = decal || {};
    const set = (patch) => onChange({ url: d.url || '', scale: d.scale ?? 0.6, opacity: d.opacity ?? 0.85, ...patch });
    return (
        <>
            <div className="te-row">
                <div className="te-row-text">
                    <div className="te-row-label">{window.t("Arquivo do logo")}</div>
                    <div className="te-row-hint">{window.t("PNG em")} <code>assets/tables/decals/</code> ({window.t("ex.:")} <code>logo.png</code>), {window.t("URL http(s) ou data:image. Vazio = sem logo.")}</div>
                </div>
                <div className="te-row-control">
                    <input type="text" className="te-text-input" placeholder="logo.png"
                        value={d.url || ''} spellCheck={false}
                        onChange={(e) => set({ url: e.target.value })}/>
                </div>
            </div>
            {d.url ? (
                <>
                    <RangeRow label={window.t("Tamanho")} hint={window.t("Lado maior do logo, em metros.")} value={d.scale ?? 0.6}
                        min={0.2} max={1.5} step={0.05} format={(v) => v.toFixed(2) + 'm'} onChange={(v) => set({ scale: v })}/>
                    <RangeRow label={window.t("Opacidade")} value={d.opacity ?? 0.85}
                        min={0.1} max={1} step={0.05} format={(v) => Math.round(v * 100) + '%'} onChange={(v) => set({ opacity: v })}/>
                    <button className="btn-ghost" style={{ alignSelf: "flex-start" }} onClick={() => onChange(null)}>{window.t("Remover logo")}</button>
                </>
            ) : null}
        </>
    );
}

function WoodPalette({ onPick }) {
    return (
        <div style={{ display: "flex", flexDirection: "column", gap: 6, padding: "6px 0" }}>
            <div>
                <div className="te-row-label">{window.t("Madeiras pré-definidas")}</div>
                <div className="te-row-hint">{window.t("Clique para aplicar gabinete + skirt + topo do trilho de uma vez.")}</div>
            </div>
            <div className="te-wood-grid">
                {getWoodPalette().map(p => (
                    <button key={p.name} className="te-wood-swatch" title={p.name} onClick={() => onPick(p)}>
                        <div className="te-wood-stack">
                            <span style={{ background: p.woodDark }}/>
                            <span style={{ background: p.woodFrame }}/>
                            <span style={{ background: p.railTop }}/>
                        </div>
                        <span className="te-wood-name">{p.name}</span>
                    </button>
                ))}
            </div>
        </div>
    );
}

function FeltPalette({ onPick, currentFelt }) {
    const vivos   = FELT_PRESETS.filter(p => p.tier === 'vivo');
    const escuros = FELT_PRESETS.filter(p => p.tier === 'escuro');
    const Section = ({ title, items }) => (
        <div>
            <div className="te-row-label" style={{ marginBottom: 4 }}>{title}</div>
            <div className="te-felt-grid">
                {items.map(p => (
                    <button key={p.name} className={`te-felt-swatch ${currentFelt === p.felt ? "sel" : ""}`}
                        title={p.name} onClick={() => onPick(p)}>
                        <span className="te-felt-fill" style={{ background: p.felt }}/>
                        <span className="te-felt-name">{p.name}</span>
                    </button>
                ))}
            </div>
        </div>
    );
    return (
        <div style={{ display: "flex", flexDirection: "column", gap: 12, padding: "6px 0" }}>
            <div>
                <div className="te-row-label">{window.t("Cores pré-definidas")}</div>
                <div className="te-row-hint">{window.t("Clique para aplicar feltro + cushion. Vivos são os atuais; escuros preservam as opções antigas.")}</div>
            </div>
            <Section title={window.t("Vivos")}   items={vivos}/>
            <Section title={window.t("Escuros")} items={escuros}/>
        </div>
    );
}

// === Mesas do jogo (navegador) ===
// Lista TABLE_THEMES via bridge (com overrides aplicados). Selecionar
// carrega a mesa no editor; "editada" marca mesas com override salvo.
function GameTablesCard({ editingId, onPick, refreshKey }) {
    const [ready, setReady] = React.useState(!!window.MastershotTablePreview?.themes);
    React.useEffect(() => {
        if (ready) return;
        const onReady = () => setReady(true);
        window.addEventListener('mastershot:table-preview-ready', onReady);
        return () => window.removeEventListener('mastershot:table-preview-ready', onReady);
    }, [ready]);

    const themes = React.useMemo(
        () => (ready ? window.MastershotTablePreview.themes.listThemes() : []),
        [ready, refreshKey]);

    return (
        <div className="te-card">
            <div className="te-card-title">{window.t("Mesas do jogo")}</div>
            <div className="te-row-hint" style={{ marginTop: -2 }}>
                {window.t("Selecione para editar a mesa real — renomear, cores, modelo e trama. Alterações valem no jogo após salvar.")}
            </div>
            {!ready && <div style={{ color: "var(--ink-400)", fontSize: 12 }}>{window.t("Carregando catálogo…")}</div>}
            <div style={{ display: "flex", flexDirection: "column", gap: 6, maxHeight: 230, overflowY: "auto" }}>
                {themes.map(({ id, theme, edited }) => (
                    <button key={id}
                        className={`te-preset-load ${editingId === id ? "te-game-sel" : ""}`}
                        onClick={() => onPick(id, theme)}>
                        <span className="te-swatch" style={{ background: theme.felt }}/>
                        <span style={{ flex: 1, textAlign: "left" }}>{theme.name}</span>
                        {edited && <span className="te-badge te-badge-gold">{window.t("editada")}</span>}
                        <span className="te-badge">{(theme.model || 'classic') === 'pro' ? 'PRO' : window.t('CLÁSSICA')}</span>
                    </button>
                ))}
            </div>
        </div>
    );
}

// === Live preview ===

const CAMERA_VIEWS = [
    { id: 'diag',    name: window.t('Diagonal') },
    { id: 'top',     name: window.t('Topo') },
    { id: 'corner',  name: window.t('Caçapa') },
    { id: 'cushion', name: window.t('Tabela') },
];

// PreviewCanvas é dono da câmera: órbita manual (arrastar/zoom), presets de
// ângulo e o auto-rotate ficam aqui, sem desync com o pai (o estado do
// auto-rotate vive junto do OrbitControls que ele controla).
function PreviewCanvas({ theme }) {
    const canvasRef = React.useRef(null);
    const previewRef = React.useRef(null);
    const [ready, setReady] = React.useState(!!window.MastershotTablePreview);
    const [autoRotate, setAutoRotate] = React.useState(true);

    // Aguarda o bridge ESM ficar pronto antes de instanciar a preview.
    React.useEffect(() => {
        if (ready) return;
        const onReady = () => setReady(true);
        window.addEventListener('mastershot:table-preview-ready', onReady);
        return () => window.removeEventListener('mastershot:table-preview-ready', onReady);
    }, [ready]);

    React.useEffect(() => {
        if (!ready || !canvasRef.current) return;
        const TP = window.MastershotTablePreview.TablePreview;
        const p = new TP(canvasRef.current);
        previewRef.current = p;
        p.onUserInteract = () => setAutoRotate(false);   // arrastar pausa o giro
        p.applyTheme(theme);
        return () => {
            p.dispose();
            previewRef.current = null;
        };
    }, [ready]);

    React.useEffect(() => {
        if (previewRef.current) previewRef.current.applyTheme(theme);
    }, [theme]);

    React.useEffect(() => {
        if (previewRef.current) previewRef.current.setAutoRotate(autoRotate);
    }, [autoRotate]);

    const goView = (id) => { previewRef.current?.setView(id); setAutoRotate(false); };

    return (
        <div style={{ position: "relative", width: "100%", height: "100%" }}>
            {!ready && (
                <div style={{
                    position: "absolute", inset: 0, display: "flex",
                    alignItems: "center", justifyContent: "center",
                    color: "var(--ink-300)", fontSize: 13, letterSpacing: "0.2em",
                }}>{window.t("Carregando preview…")}</div>
            )}
            <canvas ref={canvasRef} style={{ width: "100%", height: "100%", display: "block" }}/>
            {ready && (
                <div className="te-cam-bar">
                    {CAMERA_VIEWS.map(v => (
                        <button key={v.id} className="te-cam-btn" onClick={() => goView(v.id)}>{v.name}</button>
                    ))}
                    <label className="te-cam-rot" title={window.t("Girar a câmera automaticamente")}>
                        <input type="checkbox" checked={autoRotate} onChange={e => setAutoRotate(e.target.checked)}/>
                        {window.t("Girar")}
                    </label>
                </div>
            )}
        </div>
    );
}

// === Main screen ===

function TableEditorScreen({ navigate }) {
    const PLAYER = window.MastershotAuth.getPlayer();
    if (!PLAYER || !PLAYER.isAdmin) {
        return (
            <div style={{ padding: 80, textAlign: "center", color: "var(--ink-300)" }}>
                <div style={{ fontFamily: "var(--font-display)", fontSize: 28, color: "var(--gold-300)" }}>
                    {window.t("Acesso restrito")}
                </div>
                <button className="btn" style={{ marginTop: 24 }} onClick={() => navigate("menu")}>{window.t("Voltar")}</button>
            </div>
        );
    }

    const [theme, setTheme]   = React.useState(DEFAULT_THEME);
    const [presets, setPresets] = React.useState(() => loadPresets());
    // Mesa do jogo em edição (null = criando preset avulso)
    const [editingId, setEditingId] = React.useState(null);
    const [tablesRefresh, setTablesRefresh] = React.useState(0);
    const [toast, setToast] = React.useState('');
    const toastTimer = React.useRef(null);
    const flash = React.useCallback((msg) => {
        setToast(msg);
        if (toastTimer.current) clearTimeout(toastTimer.current);
        toastTimer.current = setTimeout(() => setToast(''), 1800);
    }, []);
    React.useEffect(() => () => { if (toastTimer.current) clearTimeout(toastTimer.current); }, []);

    // Guarda de "sujo": baseline = último tema carregado/salvo. isDirty
    // compara o tema atual. Trocar de mesa/preset/reset/voltar com edições
    // não salvas pede confirmação — antes sobrescrevia tudo em silêncio.
    const baselineRef = React.useRef(JSON.stringify(DEFAULT_THEME));
    const setBaseline = (t) => { baselineRef.current = JSON.stringify(t); };
    const isDirty = JSON.stringify(theme) !== baselineRef.current;
    const confirmDiscard = async () => !isDirty ||
        (await window.MastershotConfirm({ title: window.t('Descartar alterações?'), message: window.t('Há alterações não salvas nesta mesa. Descartar?'), confirmLabel: window.t('Descartar'), danger: true }));

    const updateField = (k, v) => setTheme(t => ({ ...t, [k]: v }));
    const themesApi = () => window.MastershotTablePreview?.themes;

    const onPickGameTable = async (id, t) => {
        if (!(await confirmDiscard())) return;
        setEditingId(id);
        const next = { ...DEFAULT_THEME, ...t };
        setTheme(next);
        setBaseline(next);
    };
    const onSaveGameTable = () => {
        const api = themesApi();
        if (!api || !editingId) return;
        const name = (theme.name || '').trim() || editingId;
        const patch = { ...theme, name };
        delete patch.savedAt;
        api.saveThemeOverride(editingId, patch);     // cache local (imediato neste navegador)
        const saved = { ...theme, name };
        setTheme(saved);
        setBaseline(saved);               // limpa o "sujo": salvar = baseline novo
        setTablesRefresh(n => n + 1);
        flash(window.t('Mesa salva — publicando no servidor…'));
        // Publica GLOBALMENTE no DB → vale pra TODOS os jogadores (não só este browser).
        if (window.__msPublishThemeOverride) {
            window.__msPublishThemeOverride(editingId, patch).then((res) => {
                if (res && res.ok) flash(window.t('✓ Publicada no servidor — vale pra todos'));
                else flash(window.t('⚠ Salva local, mas falhou publicar no servidor: {erro}', { erro: (res && res.error) || '?' }));
            });
        } else {
            flash(window.t('⚠ Salva só local (sync do servidor indisponível)'));
        }
    };
    const onRestoreGameTable = async () => {
        const api = themesApi();
        if (!api || !editingId) return;
        if (!(await window.MastershotConfirm({ title: window.t('Restaurar mesa'), message: window.t('Restaurar "{nome}" ao padrão de fábrica? As edições salvas desta mesa serão removidas.', { nome: editingId }), confirmLabel: window.t('Restaurar'), danger: true }))) return;
        api.clearThemeOverride(editingId);
        const next = { ...DEFAULT_THEME, ...api.resolveTheme(editingId) };
        setTheme(next);
        setBaseline(next);
        setTablesRefresh(n => n + 1);
        flash(window.t('Restaurada ao padrão — removendo do servidor…'));
        // Remove o override GLOBAL no DB → volta ao de fábrica pra todos.
        if (window.__msUnpublishThemeOverride) {
            window.__msUnpublishThemeOverride(editingId).then((res) => {
                if (res && res.ok) flash(window.t('✓ Restaurada ao padrão (no servidor também)'));
                else flash(window.t('⚠ Local restaurada, mas falhou remover no servidor: {erro}', { erro: (res && res.error) || '?' }));
            });
        }
    };

    const onSave = () => {
        const name = (theme.name || '').trim() || window.t('Tema #{n}', { n: presets.length + 1 });
        const saved = { ...theme, name };
        const newPreset = { ...saved, savedAt: Date.now() };
        const next = [...presets.filter(p => p.name !== name), newPreset];
        setPresets(next);
        savePresets(next);
        setTheme(saved);
        setBaseline(saved);
        flash(window.t('Preset salvo — jogável via ?table=custom:{nome}', { nome: name }));
    };
    const onLoadPreset = async (p) => {
        if (!(await confirmDiscard())) return;
        setEditingId(null);
        const next = { ...DEFAULT_THEME, ...p };
        delete next.savedAt;
        setTheme(next);
        setBaseline(next);
    };
    const onDeletePreset = async (name) => {
        if (!(await window.MastershotConfirm({ title: window.t('Excluir preset'), message: window.t('Excluir o preset "{nome}"? Esta ação não pode ser desfeita.', { nome: name }), confirmLabel: window.t('Excluir'), danger: true }))) return;
        const next = presets.filter(p => p.name !== name);
        setPresets(next);
        savePresets(next);
        flash(window.t('Preset excluído'));
    };
    const onReset = async () => {
        if (!(await confirmDiscard())) return;
        setEditingId(null);
        setTheme(DEFAULT_THEME);
        setBaseline(DEFAULT_THEME);
    };
    const onCopyJSON = () => {
        const json = JSON.stringify(theme, null, 2);
        if (navigator.clipboard?.writeText) {
            navigator.clipboard.writeText(json)
                .then(() => flash(window.t('JSON copiado')))
                .catch(() => { console.log(json); flash(window.t('Sem permissão — JSON no console')); });
        } else {
            console.log(json);
            flash(window.t('Sem clipboard (http) — JSON no console'));
        }
    };

    return (
        <div className="screen active" style={{ opacity: 1 }}>
            <AmbientBackdrop/>
            <TopBar navigate={navigate}/>

            <div style={{
                position: "relative", zIndex: 5, padding: "92px 32px 32px",
                maxWidth: 1600, margin: "0 auto",
                display: "grid", gridTemplateColumns: "minmax(360px, 420px) 1fr",
                gap: 24, height: "100vh", boxSizing: "border-box",
            }}>
                {/* ----- Coluna esquerda: form ----- */}
                <div style={{ display: "flex", flexDirection: "column", gap: 12, overflowY: "auto", paddingRight: 8 }}>
                    <button className="back-btn" onClick={async () => { if (await confirmDiscard()) navigate("admin"); }}>‹ {window.t("Voltar")}</button>

                    <div>
                        <div style={{ fontSize: 11, color: "var(--gold-500)", letterSpacing: "0.3em", textTransform: "uppercase", marginBottom: 4 }}>
                            {window.t("Admin · Editor")}
                        </div>
                        <div style={{ fontFamily: "var(--font-display)", fontSize: 26, color: "var(--ink-100)" }}>
                            {window.t("Criador de Mesas")}
                        </div>
                    </div>

                    <GameTablesCard editingId={editingId} onPick={onPickGameTable} refreshKey={tablesRefresh}/>

                    <div className="te-card">
                        {editingId && (
                            <div className="te-editing-banner">
                                {window.t("Editando mesa do jogo:")} <b>{editingId}</b>
                            </div>
                        )}
                        <div className="te-row">
                            <div className="te-row-text">
                                <div className="te-row-label">{window.t("Nome")}</div>
                                <div className="te-row-hint">{editingId ? window.t('Renomeia a mesa no jogo.') : window.t('Identificador do preset.')}</div>
                            </div>
                            <div className="te-row-control">
                                <input
                                    type="text"
                                    className="te-text-input"
                                    value={theme.name}
                                    onChange={(e) => updateField('name', e.target.value)}
                                />
                            </div>
                        </div>

                        <ToggleRow
                            label={window.t("Modelo 3D")}
                            hint={window.t("Clássica: gabinete + pernas. Pro Tournament: trilhos mitrados, castings cromados e pedestal central.")}
                            value={theme.model || 'classic'}
                            options={MODEL_OPTIONS}
                            onChange={v => updateField('model', v)}
                        />
                        <CushionStyleRow value={theme.cushionStyle} onChange={(v) => updateField('cushionStyle', v)}/>
                        {theme.cushionStyle === 'chamfered' && (<>
                            <MmSliderRow
                                label={window.t("Altura do nariz")}
                                hint={window.t("Aresta onde a bola toca. Menor = rampa mais funda/inclinada (trilho tem 40mm).")}
                                value={theme.cushionNoseH ?? 0.035}
                                min={6} max={38}
                                onChange={(v) => updateField('cushionNoseH', v)}
                            />
                            <MmSliderRow
                                label={window.t("Recuo sob o nariz")}
                                hint={window.t("Undercut da borracha — maior = fresta de sombra mais profunda junto ao pano.")}
                                value={theme.cushionUndercut ?? 0.035}
                                min={0} max={44}
                                onChange={(v) => updateField('cushionUndercut', v)}
                            />
                        </>)}
                        <ToggleRow
                            label={window.t("Estilo do trilho")}
                            hint={window.t("Cross-section do trilho superior — reto ou cantos arredondados.")}
                            value={theme.railProfile}
                            options={[{ id: 'square', name: window.t('Reto') }, { id: 'rounded', name: window.t('Arredondado') }]}
                            onChange={v => updateField('railProfile', v)}
                        />
                        <ToggleRow
                            label={window.t("Cantos do corpo")}
                            hint={window.t("Vista superior da mesa — cantos retos ou suaves.")}
                            value={theme.bodyProfile}
                            options={[{ id: 'square', name: window.t('Reto') }, { id: 'rounded', name: window.t('Arredondado') }]}
                            onChange={v => updateField('bodyProfile', v)}
                        />
                        <ToggleRow
                            label={window.t("Material do trilho")}
                            hint={window.t("Madeira usa a cor abaixo; metálicos têm paleta própria.")}
                            value={theme.railMaterial}
                            options={getRailMaterials().map(m => ({ id: m.id, name: m.name }))}
                            onChange={v => updateField('railMaterial', v)}
                        />
                    </div>

                    <div className="te-card">
                        <div className="te-card-title">{window.t("Cores do Pano")}</div>
                        <FeltPalette currentFelt={theme.felt}
                            onPick={(p) => setTheme(t => ({ ...t, felt: p.felt, cushion: p.cushion }))}/>
                        <ToggleRow
                            label={window.t("Trama do pano")}
                            hint={window.t("Tecido fotografado em escalas diferentes (edição AAA): penteada de torneio, speed lisa ou lã felpuda.")}
                            value={theme.feltWeave || 'worsted'}
                            options={WEAVE_OPTIONS}
                            onChange={v => updateField('feltWeave', v)}
                        />
                        <ColorRow label={window.t("Feltro")}     hint={window.t("Cor do tecido principal.")}          value={theme.felt}    onChange={v => updateField('felt', v)}/>
                        <ColorRow label={window.t("Cushion")}    hint={window.t("Borda interna (cushion) que a bola toca.")} value={theme.cushion} onChange={v => updateField('cushion', v)}/>
                    </div>

                    <div className="te-card">
                        <div className="te-card-title">{window.t("Detalhes")}</div>
                        <ToggleRow
                            label={window.t("Formato dos sights")}
                            hint={window.t("Losango (clássica), redondo (torneio) ou nenhum. Só visual.")}
                            value={theme.sightShape || 'auto'}
                            options={[{ id: 'auto', name: window.t('Padrão') }, { id: 'diamond', name: window.t('Losango') }, { id: 'round', name: window.t('Redondo') }, { id: 'none', name: window.t('Nenhum') }]}
                            onChange={v => updateField('sightShape', v)}
                        />
                        <ToggleRow
                            label={window.t("Spots no pano")}
                            hint={window.t("Marcas de cabeça/centro/pé sobre o feltro.")}
                            value={theme.showSpots === false ? 'hide' : 'show'}
                            options={[{ id: 'show', name: window.t('Mostrar') }, { id: 'hide', name: window.t('Ocultar') }]}
                            onChange={v => updateField('showSpots', v === 'show')}
                        />
                        <ColorRow label={window.t("Sights/diamantes")} hint={window.t("Marcadores de mira no topo do trilho.")} value={theme.accent || '#e8e4d8'} onChange={v => updateField('accent', v)}/>
                        <ColorRow label={window.t("Boca da caçapa")}   hint={window.t("Interior/forro das caçapas.")}           value={theme.pocketLining || '#101010'} onChange={v => updateField('pocketLining', v)}/>
                    </div>

                    <div className="te-card">
                        <div className="te-card-title">{window.t("Logo no pano (opcional)")}</div>
                        <DecalControls decal={theme.decal} onChange={(d) => updateField('decal', d)}/>
                    </div>

                    <div className="te-card">
                        <div className="te-card-title">{window.t("Madeira & Trilho")}</div>
                        <WoodPalette onPick={(p) => setTheme(t => ({ ...t, woodDark: p.woodDark, woodFrame: p.woodFrame, railTop: p.railTop }))}/>
                        <ColorRow label={window.t("Gabinete")}   hint={window.t("Corpo principal externo da mesa.")} value={theme.woodDark}  onChange={v => updateField('woodDark', v)}/>
                        <ColorRow label={window.t("Skirt")}      hint={window.t("Saia/moldura lateral.")}             value={theme.woodFrame} onChange={v => updateField('woodFrame', v)}/>
                        <ColorRow label={window.t("Topo do trilho")} hint={theme.railMaterial === 'wood' ? window.t("Faixa superior onde ficam os diamantes.") : window.t("Sem efeito enquanto o material do trilho não for Madeira.")} value={theme.railTop} onChange={v => updateField('railTop', v)}/>
                    </div>

                    <div className="te-card">
                        <div className="te-card-title">{window.t("Presets salvos (local)")}</div>
                        {presets.length === 0 && <div style={{ color: "var(--ink-400)", fontSize: 12 }}>{window.t("Nenhum preset salvo ainda.")}</div>}
                        <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
                            {presets.map(p => (
                                <div key={p.name} className="te-preset-row">
                                    <button className="te-preset-load" onClick={() => onLoadPreset(p)}>
                                        <span className="te-swatch" style={{ background: p.felt }}/>
                                        <span style={{ flex: 1, textAlign: "left" }}>{p.name}</span>
                                        <span style={{ fontSize: 10, color: "var(--ink-400)" }}>{p.cushionStyle}</span>
                                    </button>
                                    <button className="te-preset-del" onClick={() => onDeletePreset(p.name)} title={window.t("Remover")}>×</button>
                                </div>
                            ))}
                        </div>
                    </div>

                    {isDirty && (
                        <div className="te-dirty"><span className="te-dirty-dot"/>{window.t("Alterações não salvas")}</div>
                    )}
                    {editingId ? (
                        <div style={{ display: "flex", gap: 8 }}>
                            <button className="btn-ghost" onClick={onRestoreGameTable}>{window.t("Restaurar padrão")}</button>
                            <button className="btn-ghost" onClick={onCopyJSON}>JSON</button>
                            <button className="btn" style={{ flex: 1 }} onClick={onSaveGameTable}>{isDirty ? '● ' : ''}{window.t("Salvar na mesa do jogo")}</button>
                        </div>
                    ) : (
                        <div style={{ display: "flex", gap: 8 }}>
                            <button className="btn-ghost" onClick={onReset}>{window.t("Reset")}</button>
                            <button className="btn-ghost" onClick={onCopyJSON}>{window.t("Copiar JSON")}</button>
                            <button className="btn" style={{ flex: 1 }} onClick={onSave}>{isDirty ? '● ' : ''}{window.t("Salvar preset")}</button>
                        </div>
                    )}
                    {toast && <div className="te-toast">{toast}</div>}
                </div>

                {/* ----- Coluna direita: preview ----- */}
                <div style={{
                    border: "1px solid var(--ink-700)",
                    borderRadius: "var(--r-lg)",
                    overflow: "hidden",
                    background: "linear-gradient(180deg, #0a0905 0%, #1a140a 100%)",
                    minHeight: 520,
                    position: "relative",
                }}>
                    <PreviewCanvas theme={theme}/>
                </div>
            </div>

            <style>{`
                .te-card {
                    background: linear-gradient(180deg, var(--ink-800) 0%, var(--ink-900) 100%);
                    border: 1px solid var(--ink-700);
                    border-radius: var(--r-md);
                    padding: 14px 16px;
                    display: flex; flex-direction: column; gap: 10px;
                }
                .te-card-title {
                    font-size: 11px; color: var(--gold-500);
                    letter-spacing: 0.24em; text-transform: uppercase;
                    margin-bottom: 4px;
                }
                .te-row {
                    display: flex; align-items: center; gap: 12px;
                    padding: 6px 0;
                }
                .te-row-text { flex: 1; min-width: 0; }
                .te-row-label { font-size: 13px; color: var(--ink-100); font-weight: 500; }
                .te-row-hint  { font-size: 11px; color: var(--ink-400); margin-top: 2px; }
                .te-row-control { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
                .te-color-input {
                    width: 36px; height: 28px;
                    border: 1px solid var(--ink-600);
                    border-radius: var(--r-sm);
                    background: transparent; padding: 2px; cursor: pointer;
                }
                .te-hex-input, .te-text-input {
                    background: var(--ink-900);
                    border: 1px solid var(--ink-700);
                    color: var(--ink-100);
                    padding: 6px 10px;
                    border-radius: var(--r-sm);
                    font-family: var(--font-mono);
                    font-size: 12px;
                    width: 100px;
                }
                .te-text-input { width: 180px; font-family: inherit; font-size: 13px; }
                .te-hex-invalid {
                    border-color: #ff6b6b !important;
                    color: #ff9b9b;
                    background: rgba(255,107,107,0.06);
                }
                .te-dirty {
                    display: flex; align-items: center; gap: 7px;
                    font-size: 11px; color: var(--gold-300);
                    letter-spacing: 0.04em;
                }
                .te-dirty-dot {
                    width: 7px; height: 7px; border-radius: 50%;
                    background: var(--gold-400, #e8b949);
                    box-shadow: 0 0 6px rgba(232,185,73,0.8);
                }
                .te-cam-bar {
                    position: absolute; top: 12px; right: 12px;
                    display: flex; gap: 4px; align-items: center;
                    background: rgba(10,9,6,0.72); backdrop-filter: blur(8px);
                    border: 1px solid var(--ink-700); border-radius: 14px;
                    padding: 5px 7px;
                }
                .te-cam-btn {
                    background: var(--ink-900); border: 1px solid var(--ink-700);
                    color: var(--ink-200); font-size: 11px;
                    padding: 4px 9px; border-radius: 8px; cursor: pointer;
                    transition: all var(--t-fast);
                }
                .te-cam-btn:hover { border-color: var(--gold-700); color: var(--ink-100); }
                .te-cam-rot {
                    display: flex; align-items: center; gap: 4px;
                    font-size: 11px; color: var(--ink-200);
                    padding-left: 6px; margin-left: 2px;
                    border-left: 1px solid var(--ink-700); cursor: pointer;
                }
                .te-tab {
                    background: var(--ink-900);
                    border: 1px solid var(--ink-700);
                    color: var(--ink-200);
                    padding: 6px 14px;
                    border-radius: var(--r-sm);
                    font-size: 12px;
                    cursor: pointer;
                    transition: all var(--t-fast);
                }
                .te-tab:hover { border-color: var(--gold-700); color: var(--ink-100); }
                .te-tab-on {
                    background: var(--gold-700);
                    border-color: var(--gold-500);
                    color: var(--ink-900);
                    font-weight: 600;
                }
                .te-badge {
                    font-size: 9px; letter-spacing: 0.08em;
                    padding: 2px 6px; border-radius: 4px;
                    border: 1px solid var(--ink-600); color: var(--ink-300);
                    flex-shrink: 0;
                }
                .te-badge-gold {
                    border-color: var(--gold-700); color: var(--gold-300);
                    background: rgba(232,185,73,0.08);
                }
                .te-game-sel {
                    border-color: var(--gold-500) !important;
                    box-shadow: 0 0 0 1px var(--gold-700);
                }
                .te-editing-banner {
                    font-size: 11px; color: var(--gold-300);
                    background: rgba(232,185,73,0.07);
                    border: 1px solid var(--gold-700);
                    border-radius: var(--r-sm);
                    padding: 6px 10px;
                }
                .te-toast {
                    font-size: 12px; color: var(--ink-900);
                    background: var(--gold-500);
                    border-radius: var(--r-sm);
                    padding: 8px 12px; text-align: center;
                    font-weight: 600;
                }
                .te-preset-row {
                    display: flex; gap: 6px; align-items: stretch;
                }
                .te-preset-load {
                    flex: 1;
                    display: flex; align-items: center; gap: 10px;
                    background: var(--ink-900);
                    border: 1px solid var(--ink-700);
                    color: var(--ink-100);
                    padding: 8px 10px;
                    border-radius: var(--r-sm);
                    cursor: pointer;
                    font-size: 12px;
                    transition: all var(--t-fast);
                }
                .te-preset-load:hover { border-color: var(--gold-700); }
                .te-preset-del {
                    background: var(--ink-900);
                    border: 1px solid var(--ink-700);
                    color: var(--ink-300);
                    padding: 0 12px;
                    border-radius: var(--r-sm);
                    cursor: pointer;
                    font-size: 16px;
                    line-height: 1;
                }
                .te-preset-del:hover { color: #ff6b6b; border-color: #ff6b6b; }
                .te-swatch {
                    width: 14px; height: 14px; border-radius: 3px;
                    border: 1px solid rgba(255,255,255,0.2);
                    flex-shrink: 0;
                }
                .te-wood-grid {
                    display: grid;
                    grid-template-columns: repeat(4, 1fr);
                    gap: 6px;
                    width: 100%;
                    margin-top: 6px;
                }
                .te-wood-swatch {
                    background: var(--ink-900);
                    border: 1px solid var(--ink-700);
                    border-radius: var(--r-sm);
                    padding: 6px 4px;
                    cursor: pointer;
                    display: flex;
                    flex-direction: column;
                    align-items: center;
                    gap: 4px;
                    transition: all var(--t-fast);
                }
                .te-wood-swatch:hover {
                    border-color: var(--gold-700);
                    transform: translateY(-1px);
                }
                .te-wood-stack {
                    display: flex; gap: 2px;
                    width: 100%; height: 16px;
                    border-radius: 2px; overflow: hidden;
                    border: 1px solid rgba(255,255,255,0.08);
                }
                .te-wood-stack > span { flex: 1; display: block; }
                .te-wood-name {
                    font-size: 10px;
                    color: var(--ink-200);
                    letter-spacing: 0.04em;
                }
                /* Felt palette: igual ao wood mas grid mais largo (3 col)
                   já que cada swatch tem só 1 cor + nome em vez de stack. */
                .te-felt-grid {
                    display: grid;
                    grid-template-columns: repeat(3, 1fr);
                    gap: 6px;
                    width: 100%;
                    margin-top: 4px;
                }
                .te-felt-swatch {
                    background: var(--ink-900);
                    border: 1px solid var(--ink-700);
                    border-radius: var(--r-sm);
                    padding: 4px;
                    cursor: pointer;
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    transition: all var(--t-fast);
                }
                .te-felt-swatch:hover {
                    border-color: var(--gold-700);
                    transform: translateY(-1px);
                }
                .te-felt-swatch.sel {
                    border-color: var(--gold-500);
                    box-shadow: 0 0 0 1px var(--gold-700);
                    background: linear-gradient(180deg, rgba(232,185,73,0.08), var(--ink-900));
                }
                .te-felt-fill {
                    width: 18px; height: 18px;
                    border-radius: 3px;
                    border: 1px solid rgba(0,0,0,0.5);
                    flex-shrink: 0;
                }
                .te-felt-name {
                    font-size: 10px;
                    color: var(--ink-200);
                    letter-spacing: 0.03em;
                    text-align: left;
                    flex: 1;
                    white-space: nowrap;
                    overflow: hidden;
                    text-overflow: ellipsis;
                }
            `}</style>
        </div>
    );
}

Object.assign(window, { TableEditorScreen });
