var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
    function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
    var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
    var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
    var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
    var _, done = false;
    for (var i = decorators.length - 1; i >= 0; i--) {
        var context = {};
        for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
        for (var p in contextIn.access) context.access[p] = contextIn.access[p];
        context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
        var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
        if (kind === "accessor") {
            if (result === void 0) continue;
            if (result === null || typeof result !== "object") throw new TypeError("Object expected");
            if (_ = accept(result.get)) descriptor.get = _;
            if (_ = accept(result.set)) descriptor.set = _;
            if (_ = accept(result.init)) initializers.unshift(_);
        }
        else if (_ = accept(result)) {
            if (kind === "field") initializers.unshift(_);
            else descriptor[key] = _;
        }
    }
    if (target) Object.defineProperty(target, contextIn.name, descriptor);
    done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
    var useValue = arguments.length > 2;
    for (var i = 0; i < initializers.length; i++) {
        value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
    }
    return useValue ? value : void 0;
};
import * as plugins from '../plugins.js';
import * as appstate from '../appstate.js';
import * as interfaces from '../../dist_ts_interfaces/index.js';
import { appRouter } from '../router.js';
import { DeesElement, css, cssManager, customElement, html, state } from '@design.estate/dees-element';
// Top-level / flat views
import { OpsViewLogs } from './ops-view-logs.js';
// Overview group
import { OpsViewOverview } from './overview/ops-view-overview.js';
import { OpsViewConfig } from './overview/ops-view-config.js';
// Network group
import { OpsViewNetworkActivity } from './network/ops-view-network-activity.js';
import { OpsViewRoutes } from './network/ops-view-routes.js';
import { OpsViewRedirects } from './network/ops-view-redirects.js';
import { OpsViewSourceProfiles } from './network/ops-view-sourceprofiles.js';
import { OpsViewNetworkTargets } from './network/ops-view-networktargets.js';
import { OpsViewTargetProfiles } from './network/ops-view-targetprofiles.js';
import { OpsViewRemoteIngress } from './network/ops-view-remoteingress.js';
import { OpsViewVpn } from './network/ops-view-vpn.js';
// Email group
import { OpsViewEmails } from './email/ops-view-emails.js';
import { OpsViewEmailSecurity } from './email/ops-view-email-security.js';
import { OpsViewEmailDomains } from './email/ops-view-email-domains.js';
// Access group
import { OpsViewGatewayClients } from './access/ops-view-gatewayclients.js';
import { OpsViewApiTokens } from './access/ops-view-apitokens.js';
import { OpsViewUsers } from './access/ops-view-users.js';
// Security group
import { OpsViewSecurityOverview } from './security/ops-view-security-overview.js';
import { OpsViewSecurityBlocked } from './security/ops-view-security-blocked.js';
import { OpsViewSecurityAuthentication } from './security/ops-view-security-authentication.js';
// Domains group
import { OpsViewProviders } from './domains/ops-view-providers.js';
import { OpsViewDomains } from './domains/ops-view-domains.js';
import { OpsViewDns } from './domains/ops-view-dns.js';
import { OpsViewCertificates } from './domains/ops-view-certificates.js';
let OpsDashboard = (() => {
    let _classDecorators = [customElement('ops-dashboard')];
    let _classDescriptor;
    let _classExtraInitializers = [];
    let _classThis;
    let _classSuper = DeesElement;
    let _loginState_decorators;
    let _loginState_initializers = [];
    let _loginState_extraInitializers = [];
    let _uiState_decorators;
    let _uiState_initializers = [];
    let _uiState_extraInitializers = [];
    let _configState_decorators;
    let _configState_initializers = [];
    let _configState_extraInitializers = [];
    var OpsDashboard = class extends _classSuper {
        static { _classThis = this; }
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _loginState_decorators = [state()];
            _uiState_decorators = [state()];
            _configState_decorators = [state()];
            __esDecorate(this, null, _loginState_decorators, { kind: "accessor", name: "loginState", static: false, private: false, access: { has: obj => "loginState" in obj, get: obj => obj.loginState, set: (obj, value) => { obj.loginState = value; } }, metadata: _metadata }, _loginState_initializers, _loginState_extraInitializers);
            __esDecorate(this, null, _uiState_decorators, { kind: "accessor", name: "uiState", static: false, private: false, access: { has: obj => "uiState" in obj, get: obj => obj.uiState, set: (obj, value) => { obj.uiState = value; } }, metadata: _metadata }, _uiState_initializers, _uiState_extraInitializers);
            __esDecorate(this, null, _configState_decorators, { kind: "accessor", name: "configState", static: false, private: false, access: { has: obj => "configState" in obj, get: obj => obj.configState, set: (obj, value) => { obj.configState = value; } }, metadata: _metadata }, _configState_initializers, _configState_extraInitializers);
            __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
            OpsDashboard = _classThis = _classDescriptor.value;
            if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #loginState_accessor_storage = __runInitializers(this, _loginState_initializers, {
            identity: null,
            isLoggedIn: false,
        });
        get loginState() { return this.#loginState_accessor_storage; }
        set loginState(value) { this.#loginState_accessor_storage = value; }
        bootstrapStepper = __runInitializers(this, _loginState_extraInitializers);
        bootstrapCheckPromise;
        #uiState_accessor_storage = __runInitializers(this, _uiState_initializers, {
            activeView: 'overview',
            activeSubview: null,
            sidebarCollapsed: false,
            autoRefresh: true,
            refreshInterval: 1000,
            theme: 'light',
        });
        get uiState() { return this.#uiState_accessor_storage; }
        set uiState(value) { this.#uiState_accessor_storage = value; }
        #configState_accessor_storage = (__runInitializers(this, _uiState_extraInitializers), __runInitializers(this, _configState_initializers, {
            config: null,
            isLoading: false,
            error: null,
        }));
        get configState() { return this.#configState_accessor_storage; }
        set configState(value) { this.#configState_accessor_storage = value; }
        // Store viewTabs as a property to maintain object references (used for === selectedView identity)
        viewTabs = (__runInitializers(this, _configState_extraInitializers), [
            {
                name: 'Overview',
                iconName: 'lucide:layoutDashboard',
                subViews: [
                    { slug: 'stats', name: 'Stats', iconName: 'lucide:activity', element: OpsViewOverview },
                    { slug: 'configuration', name: 'Configuration', iconName: 'lucide:settings', element: OpsViewConfig },
                ],
            },
            {
                name: 'Network',
                iconName: 'lucide:network',
                subViews: [
                    { slug: 'activity', name: 'Network Activity', iconName: 'lucide:activity', element: OpsViewNetworkActivity },
                    { slug: 'routes', name: 'Routes', iconName: 'lucide:route', element: OpsViewRoutes },
                    { slug: 'redirects', name: 'Redirects', iconName: 'lucide:CornerDownRight', element: OpsViewRedirects },
                    { slug: 'sourceprofiles', name: 'Source Profiles', iconName: 'lucide:shieldCheck', element: OpsViewSourceProfiles },
                    { slug: 'networktargets', name: 'Network Targets', iconName: 'lucide:server', element: OpsViewNetworkTargets },
                    { slug: 'targetprofiles', name: 'Target Profiles', iconName: 'lucide:target', element: OpsViewTargetProfiles },
                    { slug: 'remoteingress', name: 'Remote Ingress', iconName: 'lucide:globe', element: OpsViewRemoteIngress },
                    { slug: 'vpn', name: 'VPN', iconName: 'lucide:shield', element: OpsViewVpn },
                ],
            },
            {
                name: 'Email',
                iconName: 'lucide:mail',
                subViews: [
                    { slug: 'log', name: 'Email Log', iconName: 'lucide:scrollText', element: OpsViewEmails },
                    { slug: 'security', name: 'Email Security', iconName: 'lucide:shieldCheck', element: OpsViewEmailSecurity },
                    { slug: 'domains', name: 'Email Domains', iconName: 'lucide:globe', element: OpsViewEmailDomains },
                ],
            },
            {
                name: 'Logs',
                iconName: 'lucide:scrollText',
                element: OpsViewLogs,
            },
            {
                name: 'Access',
                iconName: 'lucide:keyRound',
                subViews: [
                    { slug: 'gatewayclients', name: 'Gateway Clients', iconName: 'lucide:plugZap', element: OpsViewGatewayClients },
                    { slug: 'apitokens', name: 'API Tokens', iconName: 'lucide:key', element: OpsViewApiTokens },
                    { slug: 'users', name: 'Users', iconName: 'lucide:users', element: OpsViewUsers },
                ],
            },
            {
                name: 'Security',
                iconName: 'lucide:shield',
                subViews: [
                    { slug: 'overview', name: 'Overview', iconName: 'lucide:eye', element: OpsViewSecurityOverview },
                    { slug: 'blocked', name: 'Blocked IPs', iconName: 'lucide:shieldBan', element: OpsViewSecurityBlocked },
                    { slug: 'authentication', name: 'Authentication', iconName: 'lucide:lock', element: OpsViewSecurityAuthentication },
                ],
            },
            {
                name: 'Domains',
                iconName: 'lucide:globe',
                subViews: [
                    { slug: 'providers', name: 'Providers', iconName: 'lucide:plug', element: OpsViewProviders },
                    { slug: 'domains', name: 'Domains', iconName: 'lucide:globe', element: OpsViewDomains },
                    { slug: 'dns', name: 'DNS', iconName: 'lucide:list', element: OpsViewDns },
                    { slug: 'certificates', name: 'Certificates', iconName: 'lucide:badgeCheck', element: OpsViewCertificates },
                ],
            },
        ]);
        /** URL slug for a view (explicit `slug` field, or lowercased name with spaces stripped). */
        slugFor(view) {
            return view.slug ?? view.name.toLowerCase().replace(/\s+/g, '');
        }
        /** Find the parent group of a subview, or undefined for top-level views. */
        findParent(view) {
            return this.viewTabs.find((v) => v.subViews?.includes(view));
        }
        /** Look up a view (or subview) by its URL slug pair. */
        findViewBySlug(viewSlug, subSlug) {
            const top = this.viewTabs.find((v) => this.slugFor(v) === viewSlug);
            if (!top)
                return undefined;
            if (subSlug && top.subViews) {
                return top.subViews.find((sv) => this.slugFor(sv) === subSlug) ?? top;
            }
            return top;
        }
        get globalMessages() {
            const messages = [];
            const config = this.configState.config;
            if (config && !config.cache.enabled) {
                messages.push({
                    id: 'db-disabled',
                    type: 'warning',
                    message: 'Database is disabled. Creating and editing routes, profiles, targets, and API tokens is not available.',
                    dismissible: false,
                });
            }
            return messages;
        }
        /**
         * Get the current view tab based on the UI state's activeView/activeSubview.
         * Used to pass the correct selectedView to dees-simple-appdash on initial render.
         */
        get currentViewTab() {
            return (this.findViewBySlug(this.uiState.activeView, this.uiState.activeSubview) ?? this.viewTabs[0]);
        }
        constructor() {
            super();
            document.title = 'DCRouter OpsServer';
            // Subscribe to login state
            const loginSubscription = appstate.loginStatePart
                .select((stateArg) => stateArg)
                .subscribe((loginState) => {
                this.loginState = loginState;
                // Trigger data fetch when logged in
                if (loginState.isLoggedIn) {
                    appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
                    appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
                }
            });
            this.rxSubscriptions.push(loginSubscription);
            // Subscribe to config state (for global warnings)
            const configSubscription = appstate.configStatePart
                .select((stateArg) => stateArg)
                .subscribe((configState) => {
                this.configState = configState;
            });
            this.rxSubscriptions.push(configSubscription);
            // Subscribe to UI state
            const uiSubscription = appstate.uiStatePart
                .select((stateArg) => stateArg)
                .subscribe((uiState) => {
                this.uiState = uiState;
                // Sync appdash view when state changes (e.g., from URL navigation)
                this.syncAppdashView(uiState.activeView, uiState.activeSubview);
            });
            this.rxSubscriptions.push(uiSubscription);
        }
        /**
         * Sync the dees-simple-appdash view selection with the current state.
         * This is needed when the URL changes externally (back/forward, deep link).
         */
        syncAppdashView(viewSlug, subviewSlug) {
            const appDash = this.shadowRoot?.querySelector('dees-simple-appdash');
            if (!appDash)
                return;
            const targetView = this.findViewBySlug(viewSlug, subviewSlug);
            if (!targetView)
                return;
            if (appDash.selectedView === targetView)
                return;
            // Use loadView to update both selectedView and the mounted element.
            // It will dispatch view-select; our handler skips when state already matches.
            appDash.loadView(targetView);
        }
        static styles = [
            cssManager.defaultStyles,
            css `
      :host {
        display: block;
        width: 100%;
        height: 100vh;
        overflow: hidden;
      }

      .maincontainer {
        position: relative;
        width: 100%;
        height: 100%;
      }
    `,
        ];
        render() {
            return html `
      <div class="maincontainer">
        <dees-simple-login
          name="DCRouter OpsServer"
        >
          <dees-simple-appdash
            name="DCRouter OpsServer"
            .viewTabs=${this.viewTabs}
            .selectedView=${this.currentViewTab}
            .globalMessages=${this.globalMessages}
          >
          </dees-simple-appdash>
        </dees-simple-login>
      </div>
    `;
        }
        async firstUpdated() {
            const simpleLogin = this.shadowRoot.querySelector('dees-simple-login');
            simpleLogin.addEventListener('login', (e) => {
                // Handle login event
                const detail = e.detail;
                this.login(detail.data.username, detail.data.password);
            });
            // Handle view changes
            const appDash = this.shadowRoot.querySelector('dees-simple-appdash');
            if (appDash) {
                appDash.addEventListener('view-select', (e) => {
                    const view = e.detail.view;
                    const parent = this.findParent(view);
                    const currentState = appstate.uiStatePart.getState();
                    if (parent) {
                        const parentSlug = this.slugFor(parent);
                        const subSlug = this.slugFor(view);
                        // Skip if already on this exact subview — preserves URL on initial mount
                        if (currentState?.activeView === parentSlug && currentState?.activeSubview === subSlug) {
                            return;
                        }
                        appRouter.navigateToView(parentSlug, subSlug);
                    }
                    else {
                        const slug = this.slugFor(view);
                        if (currentState?.activeView === slug && !currentState?.activeSubview) {
                            return;
                        }
                        appRouter.navigateToView(slug);
                    }
                });
                // Handle logout event
                appDash.addEventListener('logout', async () => {
                    await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
                });
            }
            // Handle initial state - check if we have a stored session that's still valid
            const loginState = appstate.loginStatePart.getState();
            if (loginState.identity?.jwt) {
                if (loginState.identity.expiresAt > Date.now()) {
                    // Client-side expiry looks valid — verify with server (keypair may have changed)
                    try {
                        const verifyRequest = new plugins.domtools.plugins.typedrequest.TypedRequest('/typedrequest', 'verifyIdentity');
                        const response = await verifyRequest.fire({ identity: loginState.identity });
                        if (response.valid) {
                            // JWT confirmed valid by server
                            this.loginState = loginState;
                            await simpleLogin.switchToSlottedContent();
                            await appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
                            await appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
                            await this.ensureAdminBootstrap();
                        }
                        else {
                            // Server rejected the JWT — clear state, show login
                            await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
                        }
                    }
                    catch {
                        // Server unreachable or error — clear state, show login
                        await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
                    }
                }
                else {
                    // JWT expired, clear the stored state
                    await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
                }
            }
        }
        async login(username, password) {
            const domtools = await this.domtoolsPromise;
            console.log(`Attempting to login...`);
            const simpleLogin = this.shadowRoot.querySelector('dees-simple-login');
            const form = simpleLogin.shadowRoot.querySelector('dees-form');
            form.setStatus('pending', 'Logging in...');
            const state = await appstate.loginStatePart.dispatchAction(appstate.loginAction, {
                username,
                password,
            });
            if (state.identity) {
                console.log('Login successful');
                this.loginState = state;
                form.setStatus('success', 'Logged in!');
                await simpleLogin.switchToSlottedContent();
                await appstate.statsStatePart.dispatchAction(appstate.fetchAllStatsAction, null);
                await appstate.configStatePart.dispatchAction(appstate.fetchConfigurationAction, null);
                await this.ensureAdminBootstrap();
            }
            else {
                form.setStatus('error', 'Login failed!');
                await domtools.convenience.smartdelay.delayFor(2000);
                form.reset();
            }
        }
        async ensureAdminBootstrap() {
            if (!this.loginState.identity || this.bootstrapStepper?.isConnected) {
                return;
            }
            if (this.bootstrapCheckPromise) {
                return this.bootstrapCheckPromise;
            }
            this.bootstrapCheckPromise = (async () => {
                try {
                    const status = await appstate.getAdminBootstrapStatus();
                    if (status.needsBootstrap) {
                        await this.showAdminBootstrapStepper(status);
                    }
                }
                catch (error) {
                    console.error('Admin bootstrap status check failed:', error);
                }
                finally {
                    this.bootstrapCheckPromise = undefined;
                }
            })();
            return this.bootstrapCheckPromise;
        }
        async showAdminBootstrapStepper(statusArg) {
            const { DeesStepper } = await import('@design.estate/dees-catalog');
            this.bootstrapStepper = await DeesStepper.createAndShow({
                cancelable: false,
                steps: [
                    {
                        title: 'Create Persisted Admin',
                        content: html `
            <div style="display: grid; gap: 16px; color: var(--dees-color-text-secondary); font-size: 14px; line-height: 1.5;">
              <p style="margin: 0;">
                This router is currently using the temporary bootstrap admin. Create the first persisted admin account to continue.
              </p>
              <dees-form>
                <dees-input-text .key=${'email'} .label=${'Admin email'} .required=${true}></dees-input-text>
                <dees-input-text .key=${'name'} .label=${'Display name'}></dees-input-text>
                <dees-input-text .key=${'password'} .label=${'Password'} .required=${true} .isPasswordBool=${true}></dees-input-text>
                <dees-input-text .key=${'passwordConfirm'} .label=${'Confirm password'} .required=${true} .isPasswordBool=${true}></dees-input-text>
                <dees-input-checkbox
                  .key=${'enableIdpGlobalAuth'}
                  .label=${'Allow idp.global login for this email'}
                  .description=${'Uses https://idp.global by default; the local dcrouter account and role remain authoritative.'}
                ></dees-input-checkbox>
              </dees-form>
            </div>
          `,
                        menuOptions: [
                            {
                                name: 'Create admin',
                                action: async (stepperArg) => {
                                    const form = stepperArg.shadowRoot?.querySelector('.selected dees-form');
                                    if (!form)
                                        return;
                                    const formData = await form.collectFormData();
                                    const email = String(formData.email || '').trim();
                                    const name = String(formData.name || '').trim();
                                    const password = String(formData.password || '');
                                    const passwordConfirm = String(formData.passwordConfirm || '');
                                    if (!email || !password) {
                                        form.setStatus?.('error', 'Email and password are required.');
                                        return;
                                    }
                                    if (password !== passwordConfirm) {
                                        form.setStatus?.('error', 'Passwords do not match.');
                                        return;
                                    }
                                    try {
                                        form.setStatus?.('pending', 'Creating persisted admin...');
                                        await appstate.createInitialAdminUser({
                                            email,
                                            name,
                                            password,
                                            enableIdpGlobalAuth: Boolean(formData.enableIdpGlobalAuth),
                                        });
                                        form.setStatus?.('success', 'Persisted admin created.');
                                        await stepperArg.destroy();
                                        this.bootstrapStepper = undefined;
                                        await appstate.usersStatePart.dispatchAction(appstate.fetchUsersAction, null);
                                    }
                                    catch (error) {
                                        form.setStatus?.('error', error instanceof Error ? error.message : 'Failed to create admin.');
                                    }
                                },
                            },
                        ],
                    },
                ],
            });
        }
        static {
            __runInitializers(_classThis, _classExtraInitializers);
        }
    };
    return OpsDashboard = _classThis;
})();
export { OpsDashboard };
//# sourceMappingURL=data:application/json;base64, 