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 { DeesElement, html, customElement, css, state, cssManager, } from '@design.estate/dees-element';
import * as appstate from '../../appstate.js';
import * as interfaces from '../../../dist_ts_interfaces/index.js';
import { viewHostCss } from '../shared/css.js';
import {} from '@design.estate/dees-catalog';
import { appRouter } from '../../router.js';
let OpsViewCertificates = (() => {
    let _classDecorators = [customElement('ops-view-certificates')];
    let _classDescriptor;
    let _classExtraInitializers = [];
    let _classThis;
    let _classSuper = DeesElement;
    let _certState_decorators;
    let _certState_initializers = [];
    let _certState_extraInitializers = [];
    let _acmeState_decorators;
    let _acmeState_initializers = [];
    let _acmeState_extraInitializers = [];
    let _domainsState_decorators;
    let _domainsState_initializers = [];
    let _domainsState_extraInitializers = [];
    var OpsViewCertificates = class extends _classSuper {
        static { _classThis = this; }
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _certState_decorators = [state()];
            _acmeState_decorators = [state()];
            _domainsState_decorators = [state()];
            __esDecorate(this, null, _certState_decorators, { kind: "accessor", name: "certState", static: false, private: false, access: { has: obj => "certState" in obj, get: obj => obj.certState, set: (obj, value) => { obj.certState = value; } }, metadata: _metadata }, _certState_initializers, _certState_extraInitializers);
            __esDecorate(this, null, _acmeState_decorators, { kind: "accessor", name: "acmeState", static: false, private: false, access: { has: obj => "acmeState" in obj, get: obj => obj.acmeState, set: (obj, value) => { obj.acmeState = value; } }, metadata: _metadata }, _acmeState_initializers, _acmeState_extraInitializers);
            __esDecorate(this, null, _domainsState_decorators, { kind: "accessor", name: "domainsState", static: false, private: false, access: { has: obj => "domainsState" in obj, get: obj => obj.domainsState, set: (obj, value) => { obj.domainsState = value; } }, metadata: _metadata }, _domainsState_initializers, _domainsState_extraInitializers);
            __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
            OpsViewCertificates = _classThis = _classDescriptor.value;
            if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        #certState_accessor_storage = __runInitializers(this, _certState_initializers, appstate.certificateStatePart.getState());
        get certState() { return this.#certState_accessor_storage; }
        set certState(value) { this.#certState_accessor_storage = value; }
        #acmeState_accessor_storage = (__runInitializers(this, _certState_extraInitializers), __runInitializers(this, _acmeState_initializers, appstate.acmeConfigStatePart.getState()));
        get acmeState() { return this.#acmeState_accessor_storage; }
        set acmeState(value) { this.#acmeState_accessor_storage = value; }
        #domainsState_accessor_storage = (__runInitializers(this, _acmeState_extraInitializers), __runInitializers(this, _domainsState_initializers, appstate.domainsStatePart.getState()));
        get domainsState() { return this.#domainsState_accessor_storage; }
        set domainsState(value) { this.#domainsState_accessor_storage = value; }
        constructor() {
            super();
            __runInitializers(this, _domainsState_extraInitializers);
            const certSub = appstate.certificateStatePart.select().subscribe((newState) => {
                this.certState = newState;
            });
            this.rxSubscriptions.push(certSub);
            const acmeSub = appstate.acmeConfigStatePart.select().subscribe((newState) => {
                this.acmeState = newState;
            });
            this.rxSubscriptions.push(acmeSub);
            const domainsSub = appstate.domainsStatePart.select().subscribe((newState) => {
                this.domainsState = newState;
            });
            this.rxSubscriptions.push(domainsSub);
        }
        async connectedCallback() {
            await super.connectedCallback();
            await Promise.all([
                appstate.certificateStatePart.dispatchAction(appstate.fetchCertificateOverviewAction, null),
                appstate.acmeConfigStatePart.dispatchAction(appstate.fetchAcmeConfigAction, null),
                appstate.domainsStatePart.dispatchAction(appstate.fetchDomainsAndProvidersAction, null),
            ]);
        }
        static styles = [
            cssManager.defaultStyles,
            viewHostCss,
            css `
      .certificatesContainer {
        display: flex;
        flex-direction: column;
        gap: 24px;
      }

      .statusBadge {
        display: inline-flex;
        align-items: center;
        padding: 3px 10px;
        border-radius: 12px;
        font-size: 12px;
        font-weight: 600;
        letter-spacing: 0.02em;
        text-transform: uppercase;
      }

      .statusBadge.valid {
        background: ${cssManager.bdTheme('#dcfce7', '#14532d')};
        color: ${cssManager.bdTheme('#166534', '#4ade80')};
      }

      .statusBadge.expiring {
        background: ${cssManager.bdTheme('#fff7ed', '#431407')};
        color: ${cssManager.bdTheme('#9a3412', '#fb923c')};
      }

      .statusBadge.expired,
      .statusBadge.failed {
        background: ${cssManager.bdTheme('#fef2f2', '#450a0a')};
        color: ${cssManager.bdTheme('#991b1b', '#f87171')};
      }

      .statusBadge.provisioning {
        background: ${cssManager.bdTheme('#eff6ff', '#172554')};
        color: ${cssManager.bdTheme('#1e40af', '#60a5fa')};
      }

      .statusBadge.unknown {
        background: ${cssManager.bdTheme('#f3f4f6', '#1f2937')};
        color: ${cssManager.bdTheme('#4b5563', '#9ca3af')};
      }

      .sourceBadge {
        display: inline-flex;
        align-items: center;
        padding: 3px 8px;
        border-radius: 4px;
        font-size: 11px;
        font-weight: 500;
        background: ${cssManager.bdTheme('#f3f4f6', '#1f2937')};
        color: ${cssManager.bdTheme('#374151', '#d1d5db')};
      }

      .routePills {
        display: flex;
        flex-wrap: wrap;
        gap: 4px;
      }

      .routePill {
        display: inline-flex;
        align-items: center;
        padding: 2px 8px;
        border-radius: 4px;
        font-size: 12px;
        background: ${cssManager.bdTheme('#e0e7ff', '#1e1b4b')};
        color: ${cssManager.bdTheme('#3730a3', '#a5b4fc')};
      }

      .moreCount {
        font-size: 11px;
        color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
        padding: 2px 6px;
      }

      .errorText {
        font-size: 12px;
        color: ${cssManager.bdTheme('#991b1b', '#f87171')};
        max-width: 420px;
        line-height: 1.35;
        white-space: normal;
      }

      .errorStack {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
      }

      .backoffIndicator {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        font-size: 11px;
        color: ${cssManager.bdTheme('#9a3412', '#fb923c')};
        padding: 2px 6px;
        border-radius: 4px;
        background: ${cssManager.bdTheme('#fff7ed', '#431407')};
      }

      .expiryInfo {
        font-size: 12px;
      }

      .expiryInfo .daysLeft {
        font-size: 11px;
        color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
      }

      .expiryInfo .daysLeft.warn {
        color: ${cssManager.bdTheme('#9a3412', '#fb923c')};
      }

      .expiryInfo .daysLeft.danger {
        color: ${cssManager.bdTheme('#991b1b', '#f87171')};
      }

      .dnsWarningPanel {
        border: 1px solid ${cssManager.bdTheme('#fed7aa', '#7c2d12')};
        border-radius: 12px;
        padding: 16px;
        background: ${cssManager.bdTheme('#fff7ed', '#1c1917')};
        color: ${cssManager.bdTheme('#7c2d12', '#fdba74')};
      }

      .dnsWarningTitle {
        font-weight: 700;
        margin-bottom: 6px;
      }

      .dnsWarningText {
        font-size: 13px;
        line-height: 1.45;
        color: ${cssManager.bdTheme('#9a3412', '#fed7aa')};
      }

      .dnsWarningList {
        margin: 12px 0 0;
        padding-left: 18px;
        font-size: 13px;
        line-height: 1.5;
      }

      .dnsWarningActions {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        margin-top: 14px;
      }
    `,
        ];
        render() {
            const { summary } = this.certState;
            return html `
      <dees-heading level="3">Certificates</dees-heading>

      <div class="certificatesContainer">
        ${this.renderStatsTiles(summary)}
        ${this.renderAcmeSettingsTile()}
        ${this.renderManagedDomainWarnings()}
        ${this.renderCertificateTable()}
      </div>
    `;
        }
        renderManagedDomainWarnings() {
            const issues = this.getMissingManagedDomainIssues();
            if (issues.length === 0) {
                return html ``;
            }
            const shownIssues = issues.slice(0, 6);
            const remaining = issues.length - shownIssues.length;
            return html `
      <div class="dnsWarningPanel">
        <div class="dnsWarningTitle">DNS-01 certificate provisioning needs managed DNS domains</div>
        <div class="dnsWarningText">
          DcRouter can only create ACME TXT records for domains listed under Domains > Domains.
          Add the zone directly or import it from a DNS provider before reprovisioning certificates.
        </div>
        <ul class="dnsWarningList">
          ${shownIssues.map((issue) => html `
            <li>
              <strong>${issue.domain}</strong>: no managed DNS domain covers
              <code>${issue.challengeHost}</code>. Add/import <code>${issue.requiredDomain}</code>
              or a parent zone.
            </li>
          `)}
          ${remaining > 0 ? html `<li>${remaining} more domain${remaining === 1 ? '' : 's'} need managed DNS.</li>` : ''}
        </ul>
        <div class="dnsWarningActions">
          <dees-button @click=${() => appRouter.navigateToView('domains', 'domains')}>Manage Domains</dees-button>
          <dees-button @click=${() => appRouter.navigateToView('domains', 'providers')}>DNS Providers</dees-button>
        </div>
      </div>
    `;
        }
        getMissingManagedDomainIssues() {
            const managedDomains = this.domainsState.domains
                .map((domain) => this.normalizeDomain(domain.name))
                .filter(Boolean);
            const issues = [];
            const seen = new Set();
            for (const cert of this.certState.certificates) {
                if (!cert.canReprovision || (cert.source !== 'acme' && cert.source !== 'provision-function')) {
                    continue;
                }
                const requiredDomain = this.getAcmeChallengeDomain(cert.domain);
                if (!requiredDomain) {
                    continue;
                }
                const covered = managedDomains.some((managedDomain) => requiredDomain === managedDomain || requiredDomain.endsWith(`.${managedDomain}`));
                if (covered) {
                    continue;
                }
                const key = `${cert.domain}:${requiredDomain}`;
                if (seen.has(key)) {
                    continue;
                }
                seen.add(key);
                issues.push({
                    domain: cert.domain,
                    challengeHost: `_acme-challenge.${requiredDomain}`,
                    requiredDomain,
                });
            }
            return issues;
        }
        getAcmeChallengeDomain(domain) {
            const normalized = this.normalizeDomain(domain).replace(/^\*\.?/, '');
            const parts = normalized.split('.').filter(Boolean);
            if (parts.length >= 2 && parts.length <= 3) {
                return parts.slice(-2).join('.');
            }
            return normalized;
        }
        normalizeDomain(domain) {
            return domain.trim().toLowerCase().replace(/^\*\.?/, '').replace(/\.$/, '');
        }
        renderAcmeSettingsTile() {
            const config = this.acmeState.config;
            if (!config) {
                return html `
        <dees-settings
          .heading=${'ACME Settings'}
          .description=${'No ACME configuration yet. Click Configure to set up automated TLS certificate issuance via Let\'s Encrypt. You\'ll also need at least one DNS provider under Domains > Providers.'}
          .actions=${[{ name: 'Configure', action: () => this.showEditAcmeDialog() }]}
        ></dees-settings>
      `;
            }
            return html `
      <dees-settings
        .heading=${'ACME Settings'}
        .settingsFields=${[
                { key: 'email', label: 'Account email', value: config.accountEmail || '(not set)' },
                { key: 'status', label: 'Status', value: config.enabled ? 'enabled' : 'disabled' },
                { key: 'mode', label: 'Mode', value: config.useProduction ? 'production' : 'staging' },
                { key: 'autoRenew', label: 'Auto-renew', value: config.autoRenew ? 'on' : 'off' },
                { key: 'threshold', label: 'Renewal threshold', value: `${config.renewThresholdDays} days` },
            ]}
        .actions=${[{ name: 'Edit', action: () => this.showEditAcmeDialog() }]}
      ></dees-settings>
    `;
        }
        async showEditAcmeDialog() {
            const { DeesModal, DeesToast } = await import('@design.estate/dees-catalog');
            const current = this.acmeState.config;
            DeesModal.createAndShow({
                heading: current ? 'Edit ACME Settings' : 'Configure ACME',
                content: html `
        <dees-form>
          <dees-input-text
            .key=${'accountEmail'}
            .label=${'Account email'}
            .value=${current?.accountEmail ?? ''}
            .required=${true}
          ></dees-input-text>
          <dees-input-checkbox
            .key=${'enabled'}
            .label=${'Enabled'}
            .value=${current?.enabled ?? true}
          ></dees-input-checkbox>
          <dees-input-checkbox
            .key=${'useProduction'}
            .label=${"Use Let's Encrypt production"}
            .description=${'Uncheck to use the staging environment'}
            .value=${current?.useProduction ?? true}
          ></dees-input-checkbox>
          <dees-input-checkbox
            .key=${'autoRenew'}
            .label=${'Auto-renew certificates'}
            .value=${current?.autoRenew ?? true}
          ></dees-input-checkbox>
          <dees-input-text
            .key=${'renewThresholdDays'}
            .label=${'Renewal threshold'}
            .description=${'Number of days before expiry to trigger renewal'}
            .value=${String(current?.renewThresholdDays ?? 30)}
          ></dees-input-text>
        </dees-form>
        <p style="margin-top: 12px; font-size: 12px; opacity: 0.7;">
          Most fields take effect on the next dcrouter restart (SmartAcme is instantiated once at
          startup). Changing the account email creates a new Let's Encrypt account — only do this
          if you know what you're doing.
        </p>
      `,
                menuOptions: [
                    { name: 'Cancel', action: async (modalArg) => modalArg.destroy() },
                    {
                        name: 'Save',
                        action: async (modalArg) => {
                            const form = modalArg.shadowRoot
                                ?.querySelector('.content')
                                ?.querySelector('dees-form');
                            if (!form)
                                return;
                            const data = await form.collectFormData();
                            const email = String(data.accountEmail ?? '').trim();
                            if (!email) {
                                DeesToast.show({
                                    message: 'Account email is required',
                                    type: 'warning',
                                    duration: 2500,
                                });
                                return;
                            }
                            const threshold = parseInt(String(data.renewThresholdDays ?? '30'), 10);
                            await appstate.acmeConfigStatePart.dispatchAction(appstate.updateAcmeConfigAction, {
                                accountEmail: email,
                                enabled: Boolean(data.enabled),
                                useProduction: Boolean(data.useProduction),
                                autoRenew: Boolean(data.autoRenew),
                                renewThresholdDays: Number.isFinite(threshold) ? threshold : 30,
                            });
                            modalArg.destroy();
                        },
                    },
                ],
            });
        }
        renderStatsTiles(summary) {
            const tiles = [
                {
                    id: 'total',
                    title: 'Total Certificates',
                    value: summary.total,
                    type: 'number',
                    icon: 'lucide:ShieldHalf',
                    color: '#3b82f6',
                },
                {
                    id: 'valid',
                    title: 'Valid',
                    value: summary.valid,
                    type: 'number',
                    icon: 'lucide:Check',
                    color: '#22c55e',
                },
                {
                    id: 'expiring',
                    title: 'Expiring Soon',
                    value: summary.expiring,
                    type: 'number',
                    icon: 'lucide:Clock',
                    color: '#f59e0b',
                },
                {
                    id: 'problems',
                    title: 'Failed / Expired',
                    value: summary.failed + summary.expired,
                    type: 'number',
                    icon: 'lucide:TriangleAlert',
                    color: '#ef4444',
                },
            ];
            return html `
      <dees-statsgrid
        .tiles=${tiles}
        .minTileWidth=${200}
        .gridActions=${[
                {
                    name: 'Refresh',
                    iconName: 'lucide:RefreshCw',
                    action: async () => {
                        await appstate.certificateStatePart.dispatchAction(appstate.fetchCertificateOverviewAction, null);
                    },
                },
            ]}
      ></dees-statsgrid>
    `;
        }
        renderCertificateTable() {
            return html `
      <dees-table
        .data=${this.certState.certificates}
        .showColumnFilters=${true}
        .displayFunction=${(cert) => ({
                Domain: cert.domain,
                Routes: this.renderRoutePills(cert.routeNames),
                Status: this.renderStatusBadge(cert.status),
                Source: this.renderSourceBadge(cert.source),
                Expires: this.renderExpiry(cert.expiryDate),
                Error: this.renderError(cert),
            })}
        .dataActions=${[
                {
                    name: 'Import Certificate',
                    iconName: 'lucide:upload',
                    type: ['header'],
                    actionFunc: async () => {
                        const { DeesModal } = await import('@design.estate/dees-catalog');
                        await DeesModal.createAndShow({
                            heading: 'Import Certificate',
                            content: html `
                  <dees-form>
                    <dees-input-fileupload
                      .key=${'certJsonFile'}
                      .label=${'Certificate JSON'}
                      .description=${'Upload a .tsclass.cert.json file'}
                      .accept=${'.json'}
                      .multiple=${false}
                      .required=${true}
                    ></dees-input-fileupload>
                  </dees-form>
                `,
                            menuOptions: [
                                {
                                    name: 'Import',
                                    iconName: 'lucide:upload',
                                    action: async (modal) => {
                                        const { DeesToast } = await import('@design.estate/dees-catalog');
                                        try {
                                            const form = modal.shadowRoot.querySelector('dees-form');
                                            const formData = await form.collectFormData();
                                            const files = formData.certJsonFile;
                                            if (!files || files.length === 0) {
                                                DeesToast.show({ message: 'Please select a JSON file.', type: 'warning', duration: 3000 });
                                                return;
                                            }
                                            const file = files[0];
                                            const text = await file.text();
                                            const cert = JSON.parse(text);
                                            if (!cert.domainName || !cert.publicKey || !cert.privateKey) {
                                                DeesToast.show({ message: 'Invalid cert JSON: missing domainName, publicKey, or privateKey.', type: 'error', duration: 4000 });
                                                return;
                                            }
                                            await appstate.certificateStatePart.dispatchAction(appstate.importCertificateAction, cert);
                                            DeesToast.show({ message: `Certificate imported for ${cert.domainName}`, type: 'success', duration: 3000 });
                                            modal.destroy();
                                        }
                                        catch (err) {
                                            DeesToast.show({ message: `Import failed: ${err.message}`, type: 'error', duration: 4000 });
                                        }
                                    },
                                },
                            ],
                        });
                    },
                },
                {
                    name: 'Reprovision',
                    iconName: 'lucide:RefreshCw',
                    type: ['inRow', 'contextmenu'],
                    actionFunc: async (actionData) => {
                        const cert = actionData.item;
                        if (!cert.canReprovision) {
                            const { DeesToast } = await import('@design.estate/dees-catalog');
                            DeesToast.show({
                                message: 'This certificate source does not support reprovisioning.',
                                type: 'warning',
                                duration: 3000,
                            });
                            return;
                        }
                        const doReprovision = async (forceRenew = false) => {
                            await appstate.certificateStatePart.dispatchAction(appstate.reprovisionCertificateAction, { domain: cert.domain, forceRenew });
                            const { DeesToast } = await import('@design.estate/dees-catalog');
                            DeesToast.show({
                                message: forceRenew
                                    ? `Force renewal triggered for ${cert.domain}`
                                    : `Reprovisioning triggered for ${cert.domain}`,
                                type: 'success',
                                duration: 3000,
                            });
                        };
                        if (cert.status === 'valid') {
                            const { DeesModal } = await import('@design.estate/dees-catalog');
                            DeesModal.createAndShow({
                                heading: 'Certificate Still Valid',
                                content: html `<p style="margin: 0; line-height: 1.5;">The certificate for <strong>${cert.domain}</strong> is still valid${cert.expiryDate ? ` until ${new Date(cert.expiryDate).toLocaleDateString()}` : ''}. Do you want to force renew it now?</p>`,
                                menuOptions: [
                                    { name: 'Cancel', action: async (modalArg) => modalArg.destroy() },
                                    {
                                        name: 'Force Renew',
                                        action: async (modalArg) => {
                                            await modalArg.destroy();
                                            await doReprovision(true);
                                        },
                                    },
                                ],
                            });
                        }
                        else {
                            await doReprovision();
                        }
                    },
                },
                {
                    name: 'Export',
                    iconName: 'lucide:download',
                    type: ['inRow', 'contextmenu'],
                    actionFunc: async (actionData) => {
                        const { DeesToast } = await import('@design.estate/dees-catalog');
                        const cert = actionData.item;
                        try {
                            const response = await appstate.fetchCertificateExport(cert.domain);
                            if (response.success && response.cert) {
                                const safeDomain = cert.domain.replace(/\*/g, '_wildcard');
                                this.downloadJsonFile(`${safeDomain}.tsclass.cert.json`, response.cert);
                                DeesToast.show({ message: `Certificate exported for ${cert.domain}`, type: 'success', duration: 3000 });
                            }
                            else {
                                DeesToast.show({ message: response.message || 'Export failed', type: 'error', duration: 4000 });
                            }
                        }
                        catch (err) {
                            DeesToast.show({ message: `Export failed: ${err.message}`, type: 'error', duration: 4000 });
                        }
                    },
                },
                {
                    name: 'Delete',
                    iconName: 'lucide:trash-2',
                    type: ['inRow', 'contextmenu'],
                    actionFunc: async (actionData) => {
                        const cert = actionData.item;
                        const { DeesModal, DeesToast } = await import('@design.estate/dees-catalog');
                        await DeesModal.createAndShow({
                            heading: `Delete Certificate: ${cert.domain}`,
                            content: html `
                  <div style="padding: 20px; font-size: 14px;">
                    <p>Are you sure you want to delete the certificate data for <strong>${cert.domain}</strong>?</p>
                    <p style="color: #f59e0b; margin-top: 12px;">Note: The certificate may remain in proxy memory until the next restart or reprovisioning.</p>
                  </div>
                `,
                            menuOptions: [
                                {
                                    name: 'Delete',
                                    iconName: 'lucide:trash-2',
                                    action: async (modal) => {
                                        try {
                                            await appstate.certificateStatePart.dispatchAction(appstate.deleteCertificateAction, cert.domain);
                                            DeesToast.show({ message: `Certificate deleted for ${cert.domain}`, type: 'success', duration: 3000 });
                                            modal.destroy();
                                        }
                                        catch (err) {
                                            DeesToast.show({ message: `Delete failed: ${err.message}`, type: 'error', duration: 4000 });
                                        }
                                    },
                                },
                            ],
                        });
                    },
                },
                {
                    name: 'View Details',
                    iconName: 'fa:magnifyingGlass',
                    type: ['doubleClick', 'contextmenu'],
                    actionFunc: async (actionData) => {
                        const cert = actionData.item;
                        const { DeesModal } = await import('@design.estate/dees-catalog');
                        await DeesModal.createAndShow({
                            heading: `Certificate: ${cert.domain}`,
                            content: html `
                  <div style="padding: 20px;">
                    <dees-dataview-codebox
                      .heading=${'Certificate Details'}
                      progLang="json"
                      .codeToDisplay=${JSON.stringify(cert, null, 2)}
                    ></dees-dataview-codebox>
                  </div>
                `,
                            menuOptions: [
                                {
                                    name: 'Copy Domain',
                                    iconName: 'lucide:Copy',
                                    action: async () => {
                                        await navigator.clipboard.writeText(cert.domain);
                                    },
                                },
                            ],
                        });
                    },
                },
            ]}
        heading1="Certificate Status"
        heading2="TLS certificates by domain"
        searchable
        .pagination=${true}
        .paginationSize=${50}
        dataName="certificate"
      ></dees-table>
    `;
        }
        downloadJsonFile(filename, data) {
            const json = JSON.stringify(data, null, 2);
            const blob = new Blob([json], { type: 'application/json' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }
        renderRoutePills(routeNames) {
            const maxShow = 3;
            const visible = routeNames.slice(0, maxShow);
            const remaining = routeNames.length - maxShow;
            return html `
      <span class="routePills">
        ${visible.map((r) => html `<span class="routePill">${r}</span>`)}
        ${remaining > 0 ? html `<span class="moreCount">+${remaining} more</span>` : ''}
      </span>
    `;
        }
        renderStatusBadge(status) {
            return html `<span class="statusBadge ${status}">${status}</span>`;
        }
        renderSourceBadge(source) {
            const labels = {
                acme: 'ACME',
                'provision-function': 'Custom',
                static: 'Static',
                none: 'None',
            };
            return html `<span class="sourceBadge">${labels[source] || source}</span>`;
        }
        renderExpiry(expiryDate) {
            if (!expiryDate) {
                return html `<span style="color: ${cssManager.bdTheme('#9ca3af', '#4b5563')}">--</span>`;
            }
            const expiry = new Date(expiryDate);
            const now = new Date();
            const daysLeft = Math.ceil((expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
            const dateStr = expiry.toLocaleDateString();
            let daysClass = '';
            let daysText = '';
            if (daysLeft < 0) {
                daysClass = 'danger';
                daysText = `(expired)`;
            }
            else if (daysLeft < 30) {
                daysClass = 'warn';
                daysText = `(${daysLeft}d left)`;
            }
            else {
                daysText = `(${daysLeft}d left)`;
            }
            return html `
      <span class="expiryInfo">
        ${dateStr} <span class="daysLeft ${daysClass}">${daysText}</span>
      </span>
    `;
        }
        renderError(cert) {
            if (cert.backoffInfo) {
                const message = cert.backoffInfo.lastError || cert.error;
                return html `
        <span class="errorStack">
          ${message ? html `<span class="errorText" title=${message}>${message}</span>` : ''}
          <span class="backoffIndicator">
            ${cert.backoffInfo.failures} failure${cert.backoffInfo.failures === 1 ? '' : 's'}, retry ${this.formatRetryTime(cert.backoffInfo.retryAfter)}
          </span>
        </span>
      `;
            }
            if (cert.error) {
                return html `<span class="errorText" title=${cert.error}>${cert.error}</span>`;
            }
            return '';
        }
        formatRetryTime(retryAfter) {
            if (!retryAfter)
                return 'soon';
            const retryDate = new Date(retryAfter);
            const now = new Date();
            const diffMs = retryDate.getTime() - now.getTime();
            if (diffMs <= 0)
                return 'now';
            const diffMin = Math.ceil(diffMs / 60000);
            if (diffMin < 60)
                return `in ${diffMin}m`;
            const diffHours = Math.ceil(diffMin / 60);
            return `in ${diffHours}h`;
        }
        static {
            __runInitializers(_classThis, _classExtraInitializers);
        }
    };
    return OpsViewCertificates = _classThis;
})();
export { OpsViewCertificates };
//# sourceMappingURL=data:application/json;base64, 