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 shared from './shared/index.js';
import * as appstate from '../appstate.js';
import * as interfaces from '../../dist_ts_interfaces/index.js';
import { BackendExecutionEnvironment } from '../environments/backend-environment.js';
import { DeesElement, customElement, html, state, css, cssManager, } from '@design.estate/dees-element';
// ============================================================================
// Data transformation helpers
// Maps backend data shapes to @serve.zone/catalog component interfaces
// ============================================================================
function formatBytes(bytes) {
    if (!bytes || bytes === 0)
        return '0 B';
    const units = ['B', 'KB', 'MB', 'GB', 'TB'];
    const k = 1024;
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    const value = bytes / Math.pow(k, i);
    return `${value.toFixed(1)} ${units[i]}`;
}
function parseImageString(image) {
    const lastColon = image.lastIndexOf(':');
    const lastSlash = image.lastIndexOf('/');
    if (lastColon > lastSlash && lastColon > 0) {
        return {
            repository: image.substring(0, lastColon),
            tag: image.substring(lastColon + 1),
        };
    }
    return { repository: image, tag: 'latest' };
}
function mapStatus(status) {
    switch (status) {
        case 'running': return 'running';
        case 'starting': return 'starting';
        case 'failed': return 'error';
        case 'stopped':
        case 'stopping':
        default: return 'stopped';
    }
}
function toServiceDetail(service) {
    const parsed = parseImageString(service.image);
    return {
        name: service.name,
        status: mapStatus(service.status),
        image: service.image,
        port: service.port,
        domain: service.domain || null,
        containerId: service.containerID || '',
        created: service.createdAt ? new Date(service.createdAt).toLocaleString() : '-',
        updated: service.updatedAt ? new Date(service.updatedAt).toLocaleString() : '-',
        registry: service.useOneboxRegistry ? 'Onebox Registry' : (service.registry || 'Docker Hub'),
        repository: service.registryRepository || parsed.repository,
        tag: service.registryImageTag || parsed.tag,
    };
}
function toServiceStats(stats) {
    return {
        cpu: stats.cpuPercent,
        memory: formatBytes(stats.memoryUsed),
        memoryLimit: formatBytes(stats.memoryLimit),
        networkIn: formatBytes(stats.networkRx),
        networkOut: formatBytes(stats.networkTx),
    };
}
function parseLogs(logs) {
    if (Array.isArray(logs)) {
        return logs.map((entry) => {
            const ts = entry.timestamp
                ? (typeof entry.timestamp === 'number' ? new Date(entry.timestamp).toISOString() : String(entry.timestamp))
                : new Date().toISOString();
            const message = entry.message || String(entry);
            const level = entry.level || 'info';
            return { timestamp: ts, message, level };
        });
    }
    if (typeof logs === 'string' && logs.trim()) {
        return logs.split('\n').filter((line) => line.trim()).map((line) => {
            const match = line.match(/^(\d{4}-\d{2}-\d{2}T[\d:.]+Z?)\s+(.*)/);
            const timestamp = match ? match[1] : new Date().toISOString();
            const message = match ? match[2] : line;
            const msgLower = message.toLowerCase();
            const level = msgLower.includes('error') || msgLower.includes('fatal')
                ? 'error'
                : msgLower.includes('warn')
                    ? 'warn'
                    : 'info';
            return { timestamp, message, level };
        });
    }
    return [];
}
const defaultStats = { cpu: 0, memory: '0 B', memoryLimit: '0 B', networkIn: '0 B', networkOut: '0 B' };
let ObViewServices = (() => {
    let _classDecorators = [customElement('ob-view-services')];
    let _classDescriptor;
    let _classExtraInitializers = [];
    let _classThis;
    let _classSuper = DeesElement;
    let _servicesState_decorators;
    let _servicesState_initializers = [];
    let _servicesState_extraInitializers = [];
    let _backupsState_decorators;
    let _backupsState_initializers = [];
    let _backupsState_extraInitializers = [];
    let _currentView_decorators;
    let _currentView_initializers = [];
    let _currentView_extraInitializers = [];
    let _selectedServiceName_decorators;
    let _selectedServiceName_initializers = [];
    let _selectedServiceName_extraInitializers = [];
    let _selectedPlatformType_decorators;
    let _selectedPlatformType_initializers = [];
    let _selectedPlatformType_extraInitializers = [];
    let _workspaceOpen_decorators;
    let _workspaceOpen_initializers = [];
    let _workspaceOpen_extraInitializers = [];
    let _pendingTemplate_decorators;
    let _pendingTemplate_initializers = [];
    let _pendingTemplate_extraInitializers = [];
    let _appStoreState_decorators;
    let _appStoreState_initializers = [];
    let _appStoreState_extraInitializers = [];
    let _settingsState_decorators;
    let _settingsState_initializers = [];
    let _settingsState_extraInitializers = [];
    var ObViewServices = class extends _classSuper {
        static { _classThis = this; }
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _servicesState_decorators = [state()];
            _backupsState_decorators = [state()];
            _currentView_decorators = [state()];
            _selectedServiceName_decorators = [state()];
            _selectedPlatformType_decorators = [state()];
            _workspaceOpen_decorators = [state()];
            _pendingTemplate_decorators = [state()];
            _appStoreState_decorators = [state()];
            _settingsState_decorators = [state()];
            __esDecorate(this, null, _servicesState_decorators, { kind: "accessor", name: "servicesState", static: false, private: false, access: { has: obj => "servicesState" in obj, get: obj => obj.servicesState, set: (obj, value) => { obj.servicesState = value; } }, metadata: _metadata }, _servicesState_initializers, _servicesState_extraInitializers);
            __esDecorate(this, null, _backupsState_decorators, { kind: "accessor", name: "backupsState", static: false, private: false, access: { has: obj => "backupsState" in obj, get: obj => obj.backupsState, set: (obj, value) => { obj.backupsState = value; } }, metadata: _metadata }, _backupsState_initializers, _backupsState_extraInitializers);
            __esDecorate(this, null, _currentView_decorators, { kind: "accessor", name: "currentView", static: false, private: false, access: { has: obj => "currentView" in obj, get: obj => obj.currentView, set: (obj, value) => { obj.currentView = value; } }, metadata: _metadata }, _currentView_initializers, _currentView_extraInitializers);
            __esDecorate(this, null, _selectedServiceName_decorators, { kind: "accessor", name: "selectedServiceName", static: false, private: false, access: { has: obj => "selectedServiceName" in obj, get: obj => obj.selectedServiceName, set: (obj, value) => { obj.selectedServiceName = value; } }, metadata: _metadata }, _selectedServiceName_initializers, _selectedServiceName_extraInitializers);
            __esDecorate(this, null, _selectedPlatformType_decorators, { kind: "accessor", name: "selectedPlatformType", static: false, private: false, access: { has: obj => "selectedPlatformType" in obj, get: obj => obj.selectedPlatformType, set: (obj, value) => { obj.selectedPlatformType = value; } }, metadata: _metadata }, _selectedPlatformType_initializers, _selectedPlatformType_extraInitializers);
            __esDecorate(this, null, _workspaceOpen_decorators, { kind: "accessor", name: "workspaceOpen", static: false, private: false, access: { has: obj => "workspaceOpen" in obj, get: obj => obj.workspaceOpen, set: (obj, value) => { obj.workspaceOpen = value; } }, metadata: _metadata }, _workspaceOpen_initializers, _workspaceOpen_extraInitializers);
            __esDecorate(this, null, _pendingTemplate_decorators, { kind: "accessor", name: "pendingTemplate", static: false, private: false, access: { has: obj => "pendingTemplate" in obj, get: obj => obj.pendingTemplate, set: (obj, value) => { obj.pendingTemplate = value; } }, metadata: _metadata }, _pendingTemplate_initializers, _pendingTemplate_extraInitializers);
            __esDecorate(this, null, _appStoreState_decorators, { kind: "accessor", name: "appStoreState", static: false, private: false, access: { has: obj => "appStoreState" in obj, get: obj => obj.appStoreState, set: (obj, value) => { obj.appStoreState = value; } }, metadata: _metadata }, _appStoreState_initializers, _appStoreState_extraInitializers);
            __esDecorate(this, null, _settingsState_decorators, { kind: "accessor", name: "settingsState", static: false, private: false, access: { has: obj => "settingsState" in obj, get: obj => obj.settingsState, set: (obj, value) => { obj.settingsState = value; } }, metadata: _metadata }, _settingsState_initializers, _settingsState_extraInitializers);
            __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
            ObViewServices = _classThis = _classDescriptor.value;
            if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        static instanceCounter = 0;
        #servicesState_accessor_storage = __runInitializers(this, _servicesState_initializers, {
            services: [],
            currentService: null,
            currentHostedAppLifecycle: null,
            currentServiceLogs: [],
            currentServiceStats: null,
            platformServices: [],
            currentPlatformService: null,
            currentPlatformServiceStats: null,
            currentPlatformServiceLogs: [],
        });
        get servicesState() { return this.#servicesState_accessor_storage; }
        set servicesState(value) { this.#servicesState_accessor_storage = value; }
        #backupsState_accessor_storage = (__runInitializers(this, _servicesState_extraInitializers), __runInitializers(this, _backupsState_initializers, {
            backups: [],
            schedules: [],
        }));
        get backupsState() { return this.#backupsState_accessor_storage; }
        set backupsState(value) { this.#backupsState_accessor_storage = value; }
        #currentView_accessor_storage = (__runInitializers(this, _backupsState_extraInitializers), __runInitializers(this, _currentView_initializers, 'list'));
        get currentView() { return this.#currentView_accessor_storage; }
        set currentView(value) { this.#currentView_accessor_storage = value; }
        #selectedServiceName_accessor_storage = (__runInitializers(this, _currentView_extraInitializers), __runInitializers(this, _selectedServiceName_initializers, ''));
        get selectedServiceName() { return this.#selectedServiceName_accessor_storage; }
        set selectedServiceName(value) { this.#selectedServiceName_accessor_storage = value; }
        #selectedPlatformType_accessor_storage = (__runInitializers(this, _selectedServiceName_extraInitializers), __runInitializers(this, _selectedPlatformType_initializers, ''));
        get selectedPlatformType() { return this.#selectedPlatformType_accessor_storage; }
        set selectedPlatformType(value) { this.#selectedPlatformType_accessor_storage = value; }
        telemetryOwnerId = (__runInitializers(this, _selectedPlatformType_extraInitializers), `ob-view-services:${++ObViewServices.instanceCounter}`);
        activeServiceTelemetryName = '';
        activePlatformTelemetryType = '';
        telemetryOperationQueue = Promise.resolve();
        telemetryOperationGeneration = 0;
        #workspaceOpen_accessor_storage = __runInitializers(this, _workspaceOpen_initializers, false);
        get workspaceOpen() { return this.#workspaceOpen_accessor_storage; }
        set workspaceOpen(value) { this.#workspaceOpen_accessor_storage = value; }
        #pendingTemplate_accessor_storage = (__runInitializers(this, _workspaceOpen_extraInitializers), __runInitializers(this, _pendingTemplate_initializers, null));
        get pendingTemplate() { return this.#pendingTemplate_accessor_storage; }
        set pendingTemplate(value) { this.#pendingTemplate_accessor_storage = value; }
        #appStoreState_accessor_storage = (__runInitializers(this, _pendingTemplate_extraInitializers), __runInitializers(this, _appStoreState_initializers, {
            apps: [],
            sourceInfo: null,
            upgradeableServices: [],
            upgradeOperations: [],
        }));
        get appStoreState() { return this.#appStoreState_accessor_storage; }
        set appStoreState(value) { this.#appStoreState_accessor_storage = value; }
        #settingsState_accessor_storage = (__runInitializers(this, _appStoreState_extraInitializers), __runInitializers(this, _settingsState_initializers, {
            settings: null,
            backupPasswordConfigured: false,
            managedDcRouterStatus: null,
            storageTargets: [],
            storageClasses: [],
        }));
        get settingsState() { return this.#settingsState_accessor_storage; }
        set settingsState(value) { this.#settingsState_accessor_storage = value; }
        constructor() {
            super();
            __runInitializers(this, _settingsState_extraInitializers);
            const servicesSub = appstate.servicesStatePart
                .select((s) => s)
                .subscribe((newState) => {
                this.servicesState = newState;
            });
            this.rxSubscriptions.push(servicesSub);
            const backupsSub = appstate.backupsStatePart
                .select((s) => s)
                .subscribe((newState) => {
                this.backupsState = newState;
            });
            this.rxSubscriptions.push(backupsSub);
            const appStoreSub = appstate.appStoreStatePart
                .select((s) => s)
                .subscribe((newState) => {
                this.appStoreState = newState;
            });
            this.rxSubscriptions.push(appStoreSub);
            const settingsSub = appstate.settingsStatePart
                .select((s) => s)
                .subscribe((newState) => {
                this.settingsState = newState;
            });
            this.rxSubscriptions.push(settingsSub);
        }
        static styles = [
            cssManager.defaultStyles,
            shared.viewHostCss,
            css `
      .page-actions {
        display: flex;
        justify-content: flex-end;
        margin-bottom: 16px;
      }

      .deploy-button {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        padding: 10px 20px;
        background: ${cssManager.bdTheme('#18181b', '#fafafa')};
        color: ${cssManager.bdTheme('#fafafa', '#18181b')};
        border: none;
        border-radius: 6px;
        font-size: 14px;
        font-weight: 500;
        cursor: pointer;
        transition: opacity 200ms ease;
      }

      .deploy-button:hover {
        opacity: 0.9;
      }

      .deploy-button svg {
        width: 16px;
        height: 16px;
      }

      :host(.workspace-mode) {
        max-width: none;
        padding: 0;
        height: 100%;
        display: flex;
        flex-direction: column;
      }

      :host(.workspace-mode) ob-sectionheading {
        display: none;
      }
    `,
        ];
        async connectedCallback() {
            super.connectedCallback();
            await Promise.all([
                appstate.dispatchProtectedAction(appstate.fetchServicesAction, null),
                appstate.dispatchProtectedAction(appstate.fetchPlatformServicesAction, null),
                appstate.dispatchProtectedAction(appstate.fetchUpgradeableAppStoreServicesAction, null),
                appstate.dispatchProtectedAction(appstate.fetchAppStoreUpgradeOperationsAction, null),
                appstate.dispatchProtectedAction(appstate.fetchSettingsAction, null),
            ]);
            // If a platform service was selected from the dashboard, navigate to its detail
            const state = appstate.getRequiredState(appstate.servicesStatePart);
            if (state.currentPlatformService) {
                const type = state.currentPlatformService.type;
                appstate.servicesStatePart.setState({
                    ...state,
                    currentPlatformService: null,
                });
                this.navigateToPlatformDetail(type);
            }
        }
        async disconnectedCallback() {
            await super.disconnectedCallback();
            void this.enqueueTelemetryOperation(async () => {
                await Promise.all([
                    this.clearServiceTelemetryInternal(),
                    this.clearPlatformTelemetryInternal(),
                ]);
            }).catch((err) => console.error('Failed to clear service telemetry subscriptions:', err));
        }
        render() {
            switch (this.currentView) {
                case 'create':
                    return this.renderCreateView();
                case 'detail':
                    return this.renderDetailView();
                case 'backups':
                    return this.renderBackupsView();
                case 'platform-detail':
                    return this.renderPlatformDetailView();
                default:
                    return this.renderListView();
            }
        }
        renderListView() {
            const mappedServices = this.servicesState.services.map((s) => ({
                name: s.name,
                image: s.image,
                domain: s.domain || null,
                status: mapStatus(s.status),
            }));
            const displayStatus = (status) => {
                switch (status) {
                    case 'running': return 'Running';
                    case 'stopped': return 'Stopped';
                    case 'starting': return 'Starting...';
                    case 'stopping': return 'Stopping...';
                    case 'failed': return 'Failed';
                    case 'not-deployed': return 'Not Deployed';
                    default: return status;
                }
            };
            // Split platform services into active (running or core) and inactive (not in use)
            const activePlatformServices = this.servicesState.platformServices.filter((ps) => ps.status === 'running' || ps.status === 'starting' || ps.status === 'stopping' || ps.isCore);
            const inactivePlatformServices = this.servicesState.platformServices.filter((ps) => !ps.isCore && (ps.status === 'not-deployed' || ps.status === 'stopped' || ps.status === 'failed'));
            const mappedActivePlatformServices = activePlatformServices.map((ps) => ({
                name: ps.displayName,
                status: displayStatus(ps.status),
                running: ps.status === 'running',
                type: ps.type,
            }));
            return html `
      <ob-sectionheading>Services</ob-sectionheading>
      <div class="page-actions">
        <button class="deploy-button" @click=${() => { this.currentView = 'create'; }}>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <line x1="12" y1="5" x2="12" y2="19"></line>
            <line x1="5" y1="12" x2="19" y2="12"></line>
          </svg>
          Deploy Service
        </button>
      </div>
      <sz-services-list-view
        .services=${mappedServices}
        @service-click=${(e) => {
                this.selectedServiceName = e.detail.name || e.detail.service?.name;
                appstate.dispatchProtectedAction(appstate.fetchServiceAction, {
                    name: this.selectedServiceName,
                });
                appstate.dispatchProtectedAction(appstate.fetchServiceLogsAction, {
                    name: this.selectedServiceName,
                });
                appstate.dispatchProtectedAction(appstate.fetchServiceStatsAction, {
                    name: this.selectedServiceName,
                });
                void this.activateServiceTelemetry(this.selectedServiceName);
                this.currentView = 'detail';
            }}
        @service-action=${(e) => this.handleServiceAction(e)}
      ></sz-services-list-view>
      <ob-sectionheading style="margin-top: 32px;">Platform Services</ob-sectionheading>
      <div style="max-width: 500px;">
        ${mappedActivePlatformServices.length > 0 ? html `
          <sz-platform-services-card
            .services=${mappedActivePlatformServices}
            @service-click=${(e) => {
                const type = e.detail.type || this.servicesState.platformServices.find((ps) => ps.displayName === e.detail.name)?.type;
                if (type) {
                    this.navigateToPlatformDetail(type);
                }
            }}
          ></sz-platform-services-card>
        ` : ''}
        ${inactivePlatformServices.length > 0 ? html `
          <div style="
            background: var(--ci-shade-1, #09090b);
            border: 1px solid var(--ci-shade-2, #27272a);
            border-radius: 8px;
            padding: 20px;
            margin-top: ${mappedActivePlatformServices.length > 0 ? '12px' : '0'};
            opacity: 0.5;
          ">
            <div style="font-size: 13px; color: var(--ci-shade-4, #71717a); margin-bottom: 12px;">Available — not in use</div>
            <div style="display: flex; flex-direction: column; gap: 12px;">
              ${inactivePlatformServices.map((ps) => html `
                <div
                  style="display: flex; justify-content: space-between; align-items: center; padding: 8px 0; cursor: pointer; transition: opacity 200ms ease;"
                  @click=${() => this.navigateToPlatformDetail(ps.type)}
                >
                  <div style="display: flex; align-items: center; gap: 10px;">
                    <div style="width: 8px; height: 8px; border-radius: 50%; background: var(--ci-shade-3, #3f3f46); flex-shrink: 0;"></div>
                    <span style="font-size: 14px; font-weight: 500; color: var(--ci-shade-4, #71717a);">${ps.displayName}</span>
                  </div>
                  <span style="font-size: 13px; color: var(--ci-shade-3, #3f3f46);">${displayStatus(ps.status)}</span>
                </div>
              `)}
            </div>
          </div>
        ` : ''}
      </div>
    `;
        }
        async deployFromTemplate(template) {
            const name = template.id || template.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
            const envVars = {};
            if (template.envVars) {
                for (const ev of template.envVars) {
                    if (ev.key && ev.value)
                        envVars[ev.key] = ev.value;
                }
            }
            const serviceConfig = {
                name,
                image: template.image,
                port: template.port || 80,
                envVars,
                volumes: this.withDefaultStorageClasses(template.volumes || []),
                enableMongoDB: template.enableMongoDB || false,
                enableS3: template.enableS3 || false,
                enableClickHouse: template.enableClickHouse || false,
                enableValkey: template.enableValkey || false,
                enableMariaDB: template.enableMariaDB || false,
            };
            await appstate.dispatchProtectedAction(appstate.createServiceAction, {
                config: serviceConfig,
            });
            this.pendingTemplate = null;
            this.currentView = 'list';
        }
        renderCreateView() {
            // If we have a pending app template from the App Store, show a quick-deploy confirmation
            if (this.pendingTemplate) {
                const t = this.pendingTemplate;
                return html `
        <ob-sectionheading>Deploy ${t.name}</ob-sectionheading>
        <div style="max-width: 600px; margin: 0 auto;">
          <div style="background: var(--ci-shade-1, #09090b); border: 1px solid var(--ci-shade-2, #27272a); border-radius: 8px; padding: 24px; margin-bottom: 16px;">
            <h3 style="margin: 0 0 8px 0; font-size: 18px;">${t.name}</h3>
            <p style="margin: 0 0 16px 0; color: var(--ci-shade-5, #a1a1aa); font-size: 14px;">${t.description}</p>
            <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 12px; font-size: 13px;">
              <div><span style="color: var(--ci-shade-5, #a1a1aa);">Image:</span> <strong>${t.image}</strong></div>
              <div><span style="color: var(--ci-shade-5, #a1a1aa);">Port:</span> <strong>${t.port}</strong></div>
              <div><span style="color: var(--ci-shade-5, #a1a1aa);">Service Name:</span> <strong>${t.id}</strong></div>
              <div><span style="color: var(--ci-shade-5, #a1a1aa);">Category:</span> <strong>${t.category}</strong></div>
            </div>
            ${t.enableMongoDB || t.enableS3 || t.enableClickHouse || t.enableValkey || t.enableMariaDB ? html `
              <div style="margin-top: 12px; font-size: 13px; color: var(--ci-shade-5, #a1a1aa);">
                Platform Services:
                ${t.enableMongoDB ? html `<span style="margin-right: 8px;">MongoDB</span>` : ''}
                ${t.enableS3 ? html `<span style="margin-right: 8px;">S3</span>` : ''}
                ${t.enableClickHouse ? html `<span style="margin-right: 8px;">ClickHouse</span>` : ''}
                ${t.enableValkey ? html `<span style="margin-right: 8px;">Valkey</span>` : ''}
                ${t.enableMariaDB ? html `<span style="margin-right: 8px;">MariaDB</span>` : ''}
              </div>
            ` : ''}
          </div>
          <div style="display: flex; gap: 12px; justify-content: flex-end;">
            <button class="deploy-button" style="background: transparent; border: 1px solid var(--ci-shade-2, #27272a); color: inherit;" @click=${() => { this.pendingTemplate = null; this.currentView = 'list'; }}>Cancel</button>
            <button class="deploy-button" @click=${() => this.deployFromTemplate(t)}>Deploy ${t.name}</button>
          </div>
        </div>
      `;
            }
            return html `
      <ob-sectionheading>Create Service</ob-sectionheading>
      <sz-service-create-view
        .registries=${[]}
        @create-service=${async (e) => {
                const formConfig = e.detail;
                const serviceConfig = {
                    name: formConfig.name,
                    image: formConfig.image,
                    port: formConfig.ports?.[0]?.containerPort
                        ? parseInt(formConfig.ports[0].containerPort, 10)
                        : 80,
                    envVars: formConfig.envVars?.reduce((acc, ev) => {
                        if (ev.key)
                            acc[ev.key] = ev.value;
                        return acc;
                    }, {}),
                    volumes: this.withDefaultStorageClasses(formConfig.volumes || []),
                    enableMongoDB: formConfig.enableMongoDB || false,
                    enableS3: formConfig.enableS3 || false,
                    enableClickHouse: formConfig.enableClickHouse || false,
                    enableValkey: formConfig.enableValkey || false,
                    enableMariaDB: formConfig.enableMariaDB || false,
                };
                await appstate.dispatchProtectedAction(appstate.createServiceAction, {
                    config: serviceConfig,
                });
                this.currentView = 'list';
            }}
        @cancel=${() => {
                this.currentView = 'list';
            }}
      ></sz-service-create-view>
    `;
        }
        getDefaultStorageClassName(purposeArg) {
            return this.settingsState.storageClasses.find((storageClassArg) => {
                return storageClassArg.purpose === purposeArg && storageClassArg.isDefault;
            })?.name || (purposeArg === 'database' ? 'local-hot' : purposeArg === 'backup' ? 'local-backup' : 'local-runtime');
        }
        withDefaultStorageClasses(volumesArg) {
            const defaultStorageClass = this.getDefaultStorageClassName('runtime');
            return volumesArg.map((volumeArg) => {
                const volume = typeof volumeArg === 'string' ? { mountPath: volumeArg } : volumeArg;
                return {
                    ...volume,
                    storageClass: volume.storageClass || defaultStorageClass,
                };
            }).filter((volumeArg) => Boolean(volumeArg.mountPath));
        }
        renderDetailView() {
            const service = this.servicesState.currentService;
            const transformedService = service ? toServiceDetail(service) : null;
            const transformedStats = this.servicesState.currentServiceStats
                ? toServiceStats(this.servicesState.currentServiceStats)
                : defaultStats;
            const transformedLogs = parseLogs(this.servicesState.currentServiceLogs);
            // Check if this service has an available upgrade
            const upgradeInfo = service
                ? this.appStoreState.upgradeableServices.find((u) => u.serviceName === service.name)
                : null;
            const upgradeOperation = service
                ? this.appStoreState.upgradeOperations.find((operation) => {
                    return operation.serviceName === service.name && operation.status === 'running';
                })
                : null;
            const latestUpgradeOperation = service
                ? this.appStoreState.upgradeOperations.find((operation) => operation.serviceName === service.name)
                : null;
            return html `
      <ob-sectionheading>Service Details</ob-sectionheading>
      ${upgradeOperation ? this.renderUpgradeOperation(upgradeOperation) : ''}
      ${!upgradeOperation && latestUpgradeOperation?.status === 'failed'
                ? this.renderUpgradeOperation(latestUpgradeOperation)
                : ''}
      ${service && this.servicesState.currentHostedAppLifecycle
                ? this.renderHostedAppLifecycleCard(service, this.servicesState.currentHostedAppLifecycle)
                : ''}
      ${upgradeInfo ? html `
        <div style="
          background: linear-gradient(135deg, rgba(59, 130, 246, 0.1), rgba(139, 92, 246, 0.1));
          border: 1px solid rgba(59, 130, 246, 0.3);
          border-radius: 8px;
          padding: 16px;
          margin-bottom: 16px;
          display: flex;
          justify-content: space-between;
          align-items: center;
        ">
          <div>
            <div style="font-size: 14px; font-weight: 600; color: var(--ci-shade-7, #e4e4e7);">
              Update available: v${upgradeInfo.currentVersion} &rarr; v${upgradeInfo.latestVersion}
            </div>
            <div style="font-size: 12px; color: var(--ci-shade-4, #71717a); margin-top: 4px;">
              ${upgradeInfo.hasMigration ? 'Migration script available' : 'Config-only upgrade'}
            </div>
          </div>
          <button
            class="deploy-button"
            style="padding: 8px 16px; font-size: 13px;"
            ?disabled=${Boolean(upgradeOperation)}
            @click=${async () => {
                await appstate.dispatchProtectedAction(appstate.upgradeAppStoreServiceAction, {
                    serviceName: upgradeInfo.serviceName,
                    targetVersion: upgradeInfo.latestVersion,
                });
            }}
          >${upgradeOperation ? 'Upgrading...' : 'Upgrade'}</button>
        </div>
      ` : ''}
      <sz-service-detail-view
        .service=${transformedService}
        .logs=${transformedLogs}
        .stats=${transformedStats}
        @service-action=${(e) => this.handleServiceAction(e)}
        @request-workspace=${async (e) => {
                const name = e.detail?.service?.name || this.selectedServiceName;
                const identity = appstate.getRequiredState(appstate.loginStatePart).identity;
                if (!name || !identity)
                    return;
                try {
                    const env = new BackendExecutionEnvironment(name, identity);
                    await env.init();
                    const detailView = this.shadowRoot?.querySelector('sz-service-detail-view');
                    if (detailView) {
                        detailView.workspaceEnvironment = env;
                    }
                    this.workspaceOpen = true;
                    this.classList.add('workspace-mode');
                }
                catch (err) {
                    console.error('Failed to open workspace:', err);
                }
            }}
        @back=${() => {
                void this.clearServiceTelemetry();
                this.workspaceOpen = false;
                this.classList.remove('workspace-mode');
                this.currentView = 'list';
            }}
      ></sz-service-detail-view>
    `;
        }
        renderUpgradeOperation(operationArg) {
            const color = operationArg.status === 'failed' ? '#f87171' : '#60a5fa';
            return html `
      <div style="
        background: var(--ci-shade-1, #09090b);
        border: 1px solid ${color};
        border-radius: 8px;
        padding: 16px;
        margin-bottom: 16px;
      ">
        <div style="display: flex; justify-content: space-between; gap: 16px; align-items: flex-start;">
          <div>
            <div style="font-size: 14px; font-weight: 600; color: var(--ci-shade-7, #e4e4e7);">
              Upgrade ${operationArg.fromVersion} &rarr; ${operationArg.targetVersion}: ${operationArg.step}
            </div>
            <div style="font-size: 12px; color: var(--ci-shade-4, #71717a); margin-top: 4px;">
              ${operationArg.status === 'running' ? 'Operation is running in the background.' : operationArg.error || 'Operation finished.'}
            </div>
          </div>
          <span style="font-size: 12px; color: ${color}; text-transform: uppercase; letter-spacing: 0.04em;">
            ${operationArg.status}
          </span>
        </div>
        <div style="
          margin-top: 12px;
          padding: 10px 12px;
          background: var(--ci-shade-0, #030305);
          border-radius: 6px;
          color: var(--ci-shade-5, #a1a1aa);
          font-family: monospace;
          font-size: 12px;
          line-height: 1.5;
          max-height: 130px;
          overflow: auto;
          white-space: pre-wrap;
        ">${operationArg.progressLines.slice(-8).join('\n')}</div>
        ${operationArg.warnings.length > 0 ? html `
          <div style="margin-top: 10px; color: #fbbf24; font-size: 12px;">
            ${operationArg.warnings.join(' | ')}
          </div>
        ` : ''}
      </div>
    `;
        }
        renderHostedAppLifecycleCard(serviceArg, lifecycleArg) {
            const action = lifecycleArg.bootstrapAction;
            const upgrade = lifecycleArg.upgradeState;
            const showUpgrade = upgrade?.status === 'available' || upgrade?.status === 'running' || upgrade?.status === 'failed';
            if (!action && !showUpgrade)
                return '';
            return html `
      <div style="
        background: var(--ci-shade-1, #09090b);
        border: 1px solid ${action ? '#f59e0b' : '#60a5fa'};
        border-radius: 8px;
        padding: 16px;
        margin-bottom: 16px;
      ">
        <div style="display: flex; justify-content: space-between; gap: 16px; align-items: flex-start;">
          <div>
            <div style="font-size: 14px; font-weight: 600; color: var(--ci-shade-7, #e4e4e7);">
              Hosted App Lifecycle
            </div>
            <div style="font-size: 12px; color: var(--ci-shade-4, #71717a); margin-top: 4px;">
              Runtime reports from ${lifecycleArg.appName || serviceArg.name}${lifecycleArg.publicUrl ? html ` at ${lifecycleArg.publicUrl}` : ''}.
            </div>
          </div>
          <span style="font-size: 12px; color: var(--ci-shade-4, #71717a); text-transform: uppercase; letter-spacing: 0.04em;">
            ${lifecycleArg.runtimeStatus || 'unknown'}
          </span>
        </div>

        ${action ? html `
          <div style="margin-top: 14px; padding: 12px; background: var(--ci-shade-0, #030305); border-radius: 6px;">
            <div style="font-size: 13px; font-weight: 600; color: var(--ci-shade-7, #e4e4e7); margin-bottom: 8px;">
              ${action.label} ${action.status === 'completed' ? '(completed)' : ''}
            </div>
            ${action.message ? html `<div style="font-size: 12px; color: var(--ci-shade-5, #a1a1aa); margin-bottom: 8px;">${action.message}</div>` : ''}
            ${action.url ? this.renderHostedAppValueRow('Setup URL', action.url) : ''}
            ${action.username ? this.renderHostedAppValueRow('Username', action.username) : ''}
            ${action.password ? this.renderHostedAppValueRow('Password', action.password) : ''}
            ${action.expiresAt ? html `
              <div style="font-size: 12px; color: var(--ci-shade-4, #71717a); margin-top: 8px;">
                Expires ${new Date(action.expiresAt).toLocaleString()}
              </div>
            ` : ''}
            <div style="font-size: 12px; color: #fbbf24; margin-top: 10px;">
              Mark done only after you saved the information or completed the app setup. This deletes the displayed bootstrap data from Onebox.
            </div>
            <button
              class="deploy-button"
              style="margin-top: 12px; padding: 8px 14px; font-size: 12px; background: transparent; border: 1px solid #f59e0b; color: #fbbf24;"
              @click=${() => this.handleDismissHostedAppBootstrap(serviceArg.name)}
            >Mark done and delete</button>
          </div>
        ` : ''}

        ${showUpgrade ? html `
          <div style="margin-top: ${action ? '12px' : '14px'}; padding: 12px; background: var(--ci-shade-0, #030305); border-radius: 6px;">
            <div style="font-size: 13px; font-weight: 600; color: var(--ci-shade-7, #e4e4e7);">
              Managed upgrade: ${upgrade.status}
            </div>
            <div style="font-size: 12px; color: var(--ci-shade-5, #a1a1aa); margin-top: 4px;">
              ${upgrade.currentVersion || '-'} ${upgrade.targetVersion || upgrade.latestVersion ? html `&rarr; ${upgrade.targetVersion || upgrade.latestVersion}` : ''}
            </div>
            ${upgrade.error ? html `<div style="font-size: 12px; color: #f87171; margin-top: 6px;">${upgrade.error}</div>` : ''}
          </div>
        ` : ''}
      </div>
    `;
        }
        renderHostedAppValueRow(labelArg, valueArg) {
            return html `
      <div style="display: grid; grid-template-columns: 110px 1fr auto; gap: 8px; align-items: center; margin-top: 6px;">
        <span style="font-size: 12px; color: var(--ci-shade-4, #71717a);">${labelArg}</span>
        <code style="font-size: 12px; color: var(--ci-shade-7, #e4e4e7); overflow-wrap: anywhere;">${valueArg}</code>
        <button
          class="deploy-button"
          style="padding: 4px 8px; font-size: 11px; background: transparent; border: 1px solid var(--ci-shade-3, #3f3f46); color: var(--ci-shade-6, #d4d4d8);"
          @click=${() => this.copyHostedAppValue(valueArg)}
        >Copy</button>
      </div>
    `;
        }
        async copyHostedAppValue(valueArg) {
            await navigator.clipboard?.writeText(valueArg);
        }
        async handleDismissHostedAppBootstrap(serviceNameArg) {
            if (!confirm('Delete the hosted app bootstrap information from Onebox?'))
                return;
            await appstate.dispatchProtectedAction(appstate.dismissHostedAppBootstrapAction, {
                name: serviceNameArg,
            });
        }
        renderBackupsView() {
            return html `
      <ob-sectionheading>Backups</ob-sectionheading>
      <sz-services-backups-view
        .schedules=${this.backupsState.schedules}
        .backups=${this.backupsState.backups}
        @create-schedule=${(e) => {
                appstate.dispatchProtectedAction(appstate.createScheduleAction, {
                    config: e.detail,
                });
            }}
        @run-now=${(e) => {
                appstate.dispatchProtectedAction(appstate.triggerScheduleAction, {
                    scheduleId: e.detail.scheduleId,
                });
            }}
        @delete-backup=${(e) => {
                appstate.dispatchProtectedAction(appstate.deleteBackupAction, {
                    backupId: e.detail.backupId,
                });
            }}
      ></sz-services-backups-view>
    `;
        }
        navigateToPlatformDetail(type) {
            void this.clearServiceTelemetry();
            // Reset to list first to force fresh DOM for dees-chart-log
            this.currentView = 'list';
            this.selectedPlatformType = type;
            // Clear previous stats/logs before fetching new ones
            appstate.servicesStatePart.setState({
                ...appstate.getRequiredState(appstate.servicesStatePart),
                currentPlatformServiceStats: null,
                currentPlatformServiceLogs: [],
            });
            // Fetch stats and logs for this platform service
            const serviceType = type;
            appstate.dispatchProtectedAction(appstate.fetchPlatformServiceStatsAction, { serviceType });
            appstate.dispatchProtectedAction(appstate.fetchPlatformServiceLogsAction, { serviceType });
            void this.activatePlatformTelemetry(serviceType);
            // Switch to detail view on next microtask (ensures fresh DOM)
            requestAnimationFrame(() => {
                this.currentView = 'platform-detail';
            });
        }
        renderPlatformDetailView() {
            const platformService = this.servicesState.platformServices.find((ps) => ps.type === this.selectedPlatformType);
            const stats = this.servicesState.currentPlatformServiceStats;
            const metrics = {
                cpu: stats ? Math.round(stats.cpuPercent) : 0,
                memory: stats ? Math.round(stats.memoryPercent) : 0,
                storage: 0,
                connections: undefined,
            };
            // Real service info per platform type
            const serviceInfo = {
                mongodb: { host: 'onebox-mongodb', port: 27017, version: '4.4', config: { engine: 'WiredTiger', authEnabled: true } },
                smartstorage: { host: 'onebox-smartstorage', port: 9000, version: 'latest', config: { controlPort: 3000, region: 'us-east-1' } },
                clickhouse: { host: 'onebox-clickhouse', port: 8123, version: 'latest', config: { nativePort: 9000, httpPort: 8123 } },
                coretraffic: { host: 'onebox-coretraffic', port: 80, version: 'latest', config: { httpsPort: 443, adminApi: 2019 } },
                mariadb: { host: 'onebox-mariadb', port: 3306, version: '11', config: { engine: 'InnoDB', authEnabled: true } },
                valkey: { host: 'onebox-valkey', port: 6379, version: '9.1.0-alpine', config: { appendonly: true, maxDatabases: 16 } },
            };
            const info = platformService
                ? serviceInfo[platformService.type] || { host: 'unknown', port: 0, version: '', config: {} }
                : { host: '', port: 0, version: '', config: {} };
            // Map backend status to catalog-compatible status
            const mapPlatformStatus = (status) => {
                switch (status) {
                    case 'running': return 'running';
                    case 'failed': return 'error';
                    case 'starting':
                    case 'stopping':
                    case 'stopped':
                    case 'not-deployed':
                    default: return 'stopped';
                }
            };
            return html `
      <ob-sectionheading>Platform Service</ob-sectionheading>
      <div class="page-actions" style="justify-content: flex-start;">
        <button class="deploy-button" style="background: transparent; border: 1px solid var(--ci-shade-2, #27272a); color: inherit;" @click=${async () => {
                await this.clearPlatformTelemetry();
                this.currentView = 'list';
            }}>
          &larr; Back to Services
        </button>
      </div>
      <sz-platform-service-detail-view
        .service=${platformService
                ? {
                    id: platformService.type,
                    name: platformService.displayName,
                    type: platformService.type,
                    status: mapPlatformStatus(platformService.status),
                    version: info.version,
                    host: info.host,
                    port: info.port,
                    config: info.config,
                    metrics,
                }
                : null}
        .logs=${this.servicesState.currentPlatformServiceLogs.map((log) => ({
                timestamp: new Date(log.timestamp).toISOString(),
                level: log.level,
                message: log.message,
            }))}
        @back=${() => {
                void this.clearPlatformTelemetry();
                this.currentView = 'list';
            }}
        @start=${async () => {
                await appstate.dispatchProtectedAction(appstate.startPlatformServiceAction, {
                    serviceType: this.selectedPlatformType,
                });
                // Refresh stats after starting
                appstate.dispatchProtectedAction(appstate.fetchPlatformServiceStatsAction, {
                    serviceType: this.selectedPlatformType,
                });
            }}
        @stop=${async () => {
                await appstate.dispatchProtectedAction(appstate.stopPlatformServiceAction, {
                    serviceType: this.selectedPlatformType,
                });
            }}
        @restart=${async () => {
                await appstate.dispatchProtectedAction(appstate.stopPlatformServiceAction, {
                    serviceType: this.selectedPlatformType,
                });
                await appstate.dispatchProtectedAction(appstate.startPlatformServiceAction, {
                    serviceType: this.selectedPlatformType,
                });
                appstate.dispatchProtectedAction(appstate.fetchPlatformServiceStatsAction, {
                    serviceType: this.selectedPlatformType,
                });
            }}
      ></sz-platform-service-detail-view>
    `;
        }
        enqueueTelemetryOperation(operationArg) {
            const generation = ++this.telemetryOperationGeneration;
            const operation = this.telemetryOperationQueue
                .catch(() => undefined)
                .then(() => operationArg(generation));
            this.telemetryOperationQueue = operation.catch(() => undefined);
            return operation;
        }
        isTelemetryOperationCurrent(generationArg) {
            return this.isConnected && generationArg === this.telemetryOperationGeneration;
        }
        async activateServiceTelemetry(serviceNameArg) {
            await this.enqueueTelemetryOperation(async (generation) => {
                if (this.activeServiceTelemetryName === serviceNameArg && !this.activePlatformTelemetryType)
                    return;
                await this.clearPlatformTelemetryInternal();
                if (this.activeServiceTelemetryName && this.activeServiceTelemetryName !== serviceNameArg) {
                    await this.clearServiceTelemetryInternal();
                }
                if (!this.isTelemetryOperationCurrent(generation))
                    return;
                this.activeServiceTelemetryName = serviceNameArg;
                await Promise.all([
                    appstate.subscribeTelemetryTarget({ type: 'serviceLogs', serviceName: serviceNameArg }, this.telemetryOwnerId),
                    appstate.subscribeTelemetryTarget({ type: 'serviceMetrics', serviceName: serviceNameArg }, this.telemetryOwnerId),
                ]);
                if (!this.isTelemetryOperationCurrent(generation) || this.activeServiceTelemetryName !== serviceNameArg) {
                    if (this.activeServiceTelemetryName === serviceNameArg) {
                        this.activeServiceTelemetryName = '';
                    }
                    await Promise.all([
                        appstate.unsubscribeTelemetryTarget({ type: 'serviceLogs', serviceName: serviceNameArg }, this.telemetryOwnerId),
                        appstate.unsubscribeTelemetryTarget({ type: 'serviceMetrics', serviceName: serviceNameArg }, this.telemetryOwnerId),
                    ]);
                }
            });
        }
        async clearServiceTelemetry() {
            await this.enqueueTelemetryOperation(async () => {
                await this.clearServiceTelemetryInternal();
            });
        }
        async clearServiceTelemetryInternal() {
            if (!this.activeServiceTelemetryName)
                return;
            const serviceName = this.activeServiceTelemetryName;
            this.activeServiceTelemetryName = '';
            await Promise.all([
                appstate.unsubscribeTelemetryTarget({ type: 'serviceLogs', serviceName }, this.telemetryOwnerId),
                appstate.unsubscribeTelemetryTarget({ type: 'serviceMetrics', serviceName }, this.telemetryOwnerId),
            ]);
        }
        async activatePlatformTelemetry(serviceTypeArg) {
            await this.enqueueTelemetryOperation(async (generation) => {
                if (this.activePlatformTelemetryType === serviceTypeArg && !this.activeServiceTelemetryName)
                    return;
                await this.clearServiceTelemetryInternal();
                if (this.activePlatformTelemetryType && this.activePlatformTelemetryType !== serviceTypeArg) {
                    await this.clearPlatformTelemetryInternal();
                }
                if (!this.isTelemetryOperationCurrent(generation))
                    return;
                this.activePlatformTelemetryType = serviceTypeArg;
                await Promise.all([
                    appstate.subscribeTelemetryTarget({ type: 'platformServiceLogs', serviceType: serviceTypeArg }, this.telemetryOwnerId),
                    appstate.subscribeTelemetryTarget({ type: 'platformServiceMetrics', serviceType: serviceTypeArg }, this.telemetryOwnerId),
                ]);
                if (!this.isTelemetryOperationCurrent(generation) || this.activePlatformTelemetryType !== serviceTypeArg) {
                    if (this.activePlatformTelemetryType === serviceTypeArg) {
                        this.activePlatformTelemetryType = '';
                    }
                    await Promise.all([
                        appstate.unsubscribeTelemetryTarget({ type: 'platformServiceLogs', serviceType: serviceTypeArg }, this.telemetryOwnerId),
                        appstate.unsubscribeTelemetryTarget({ type: 'platformServiceMetrics', serviceType: serviceTypeArg }, this.telemetryOwnerId),
                    ]);
                }
            });
        }
        async clearPlatformTelemetry() {
            await this.enqueueTelemetryOperation(async () => {
                await this.clearPlatformTelemetryInternal();
            });
        }
        async clearPlatformTelemetryInternal() {
            if (!this.activePlatformTelemetryType)
                return;
            const serviceType = this.activePlatformTelemetryType;
            this.activePlatformTelemetryType = '';
            await Promise.all([
                appstate.unsubscribeTelemetryTarget({ type: 'platformServiceLogs', serviceType }, this.telemetryOwnerId),
                appstate.unsubscribeTelemetryTarget({ type: 'platformServiceMetrics', serviceType }, this.telemetryOwnerId),
            ]);
        }
        async handleServiceAction(e) {
            const action = e.detail.action;
            const name = e.detail.service?.name || e.detail.name || this.selectedServiceName;
            switch (action) {
                case 'start':
                    await appstate.dispatchProtectedAction(appstate.startServiceAction, { name });
                    break;
                case 'stop':
                    await appstate.dispatchProtectedAction(appstate.stopServiceAction, { name });
                    break;
                case 'restart':
                    await appstate.dispatchProtectedAction(appstate.restartServiceAction, { name });
                    break;
                case 'delete':
                    if (this.activeServiceTelemetryName === name) {
                        await this.clearServiceTelemetry();
                    }
                    await appstate.dispatchProtectedAction(appstate.deleteServiceAction, { name });
                    this.currentView = 'list';
                    break;
            }
        }
        static {
            __runInitializers(_classThis, _classExtraInitializers);
        }
    };
    return ObViewServices = _classThis;
})();
export { ObViewServices };
//# sourceMappingURL=data:application/json;base64, 