// ==========================================
// Switchboard Core — SDK Entry Point
// ==========================================
// Assembles all SDK modules into the `sw` object
// and runs the boot sequence.
//
// Usage:
//   import { boot } from './js/sw/sdk/index.js';
//   const sw = await boot();
//
// Exports: boot() → window.sw
// ==========================================

import { createRestClient } from './rest-client.js';
import { createAuth }       from './auth.js';
import { createCan }        from './can.js';
import { createDomains }    from './api-domains.js';
import { createEvents }     from './events.js';
import { createPipe }       from './pipe.js';
import { createTheme }      from './theme.js';
import { createStorage }    from './storage.js';
import { createSlots }      from './slots.js';
import { createActions }    from './actions.js';
import { confirm }          from '../primitives/confirm.js';
import { prompt }           from '../primitives/prompt.js';

/**
 * Boot the SDK. Assembles modules, loads auth state, connects WebSocket.
 * Idempotent — returns the same sw object on subsequent calls.
 *
 * @returns {Promise<object>} sw
 */
export async function boot() {
    // Idempotent
    if (window.sw?._sdk) return window.sw;

    // 1. Auth — owns token state
    const auth = createAuth();

    // 2. REST client — uses auth for token injection + refresh
    const restClient = createRestClient(
        () => auth._getToken(),
        () => auth._onRefresh(),
        () => auth._on401Failure()
    );

    // 3. Wire rest client into auth (auth needs it for login/refresh/permissions calls)
    auth._setRestClient(restClient);

    // 4. Events — with WS auth callback
    const events = createEvents(async () => {
        // Prefer ticket exchange
        try {
            const data = await restClient.post('/api/v1/ws/ticket', {});
            if (data?.ticket) return `ticket=${encodeURIComponent(data.ticket)}`;
        } catch (_) { /* fall through to legacy */ }
        // Legacy fallback: JWT in query param
        const token = auth._getToken();
        return token ? `token=${encodeURIComponent(token)}` : null;
    });

    // 5. Wire emit into auth
    auth._setEmit(events.emit.bind(events));

    // 6. Remaining modules
    const { can, isAdmin, isTeamAdmin } = createCan(auth);
    const api     = createDomains(restClient);
    const pipe    = createPipe();
    const theme   = createTheme(events.emit.bind(events));
    const storage = createStorage();
    const slots   = createSlots(events.emit.bind(events));
    const actions = createActions(events.emit.bind(events));

    // 7. Assemble sw object
    const sw = Object.create(null);

    // Auth
    sw.auth = auth;

    // API domains
    sw.api = api;

    // RBAC
    sw.can = can;
    Object.defineProperty(sw, 'isAdmin', {
        get() { return isAdmin(); },
        enumerable: true,
    });
    sw.isTeamAdmin = isTeamAdmin;

    // Events (expose as top-level convenience + events namespace for connect/disconnect)
    sw.on   = events.on.bind(events);
    sw.once = events.once.bind(events);
    sw.off  = events.off.bind(events);
    sw.emit = events.emit.bind(events);
    sw.events = events;

    // Pipe, Theme, Storage, Slots, Actions
    sw.pipe    = pipe;
    sw.theme   = theme;
    sw.storage = storage;
    sw.slots   = slots;
    sw.actions = actions;

    // Shell helpers — imperative confirm/prompt backed by primitives
    sw.confirm = confirm;
    sw.prompt  = prompt;

    // Shell — layout utilities (decouples surface code from shell DOM)
    const _shell = {
        /** CSS transform scale on #surfaceInner (appearance zoom). */
        getScale() {
            const el = document.getElementById('surfaceInner');
            if (!el) return 1;
            const t = getComputedStyle(el).transform;
            if (!t || t === 'none') return 1;
            const m = t.match(/matrix\(([^,]+)/);
            return m ? parseFloat(m[1]) || 1 : 1;
        },
        /** Topbar — set after dynamic import below */
        Topbar: null,
    };
    sw.shell = _shell;

    // Toast — dynamic import to avoid module resolution issues
    try {
        const toastMod = await import('../primitives/toast.js');
        sw.toast = toastMod.toast;
        events.on('toast', ({ message, variant, duration }) => {
            toastMod.toast(message, variant, duration);
        });
    } catch (e) {
        console.warn('[sw] Toast import failed:', e.message);
    }

    // UI primitives — extensions use sw.ui.Button, sw.ui.Dialog, etc.
    try {
        const primitives = await import('../primitives/index.js');
        sw.ui = Object.freeze({ ...primitives });
    } catch (e) {
        console.warn('[sw] Primitives import failed:', e.message);
        sw.ui = Object.freeze({});
    }

    // Topbar — standard navigation bar for surfaces
    try {
        const topbarMod = await import('../shell/topbar.js');
        _shell.Topbar = topbarMod.Topbar;
    } catch (e) {
        console.warn('[sw] Topbar import failed:', e.message);
    }

    // Freeze shell now that Topbar is loaded
    sw.shell = Object.freeze(_shell);

    // UserMenu render helper — surfaces call sw.userMenu(container, opts)
    sw.userMenu = function (container, opts = {}) {
        import('../shell/user-menu.js').then(({ UserMenu }) => {
            const { render } = preact;
            render(html`<${UserMenu} ...${opts} />`, container);
        });
    };

    // Marker for idempotency
    sw._sdk = '0.2.3';

    // 8. Expose globally
    window.sw = sw;

    // 9. Boot sequence
    theme.init();

    try {
        await auth.boot();
    } catch (e) {
        console.warn('[sw] Auth boot failed (expected without backend):', e.message);
    }

    if (auth.isAuthenticated) {
        const BASE = window.__BASE__ || '';
        events.connect(BASE + '/ws');
    }

    // 10. Signal ready
    events.emit('sdk.ready', {}, { localOnly: true });
    document.dispatchEvent(new CustomEvent('sw:ready', { detail: { sw } }));
    console.log(`[sw] SDK v${sw._sdk} ready`);

    return sw;
}
