import { __decorate } from "tslib";
import { Certificate, CertificateFile } from "@api-client/core/build/browser.js";
import { html, nothing } from "lit";
import { property, state } from "lit/decorators.js";
import { live } from "lit/directives/live.js";
import { Events } from "../../events/Events.js";
import ApiElement from "../ApiElement.js";
import styles from './CertificateAdd.styles.js';
import { FileUtils } from "../../lib/files/FileUtils.js";
import { SnackNotifications } from "../../ui/notification/SnackNotifications.js";
import '../../define/ui/ui-segmented-button.js';
import '../../define/ui/ui-segmented-button-set.js';
import '../../define/ui/ui-text-field.js';
import '../../define/ui/ui-button.js';
import '../../define/ui/ui-icon.js';
import '../../define/ui/ui-progress.js';
/**
 * An element that renders a certificate import UI.
 *
 * Notes for implementation:
 * - `p12` is a single file, may have a passphrase
 * - `pem` is 2 files: the certificate and the key
 * - `pem` may have a `passphrase` on the key but not on the certificate.
 */
export default class CertificateAdd extends ApiElement {
    constructor() {
        super(...arguments);
        /**
         * The type of the certificate to import.
         * @attribute
         */
        this.importType = 'pem';
    }
    static get styles() {
        return styles;
    }
    get hasKeyImport() {
        return this.importType === 'pem';
    }
    get hasCertificatePasswordInput() {
        return this.importType === 'p12';
    }
    handleViewSelection(e) {
        if (!e.detail.selected) {
            return;
        }
        const button = e.detail.button;
        const type = button.dataset.value;
        if (type) {
            this.importType = type;
        }
    }
    handleNameChange(e) {
        const input = e.target;
        this.certificateName = input.value;
    }
    handleCertificatePasswordChange(e) {
        const input = e.target;
        this.certificatePassword = input.value;
    }
    handleKeyPasswordChange(e) {
        const input = e.target;
        this.keyPassword = input.value;
    }
    handleSelectCertificate() {
        this.selectCertificateFLow();
    }
    handleSelectKey() {
        this.selectKeyFLow();
    }
    async selectCertificateFLow() {
        this.working = true;
        const options = {
            multiple: false,
            title: 'Select a certificate file',
            filters: [{
                    description: 'Certificate files',
                    accept: {},
                }],
        };
        const filters = options.filters;
        if (this.importType === 'p12') {
            filters[0].accept = {
                'application/x-pkcs12': ['.p12', '.pfx'],
            };
        }
        else {
            filters[0].accept = {
                'application/x-pem-file': ['.pem', '.crt', '.cer', '.key'],
            };
        }
        const pickResult = await Events.Filesystem.requestOpenFile(options, this);
        if (!pickResult || pickResult.canceled) {
            this.working = false;
            return;
        }
        const [path] = pickResult.filePath;
        const readResult = await Events.Filesystem.readFile(path, { returnType: 'buffer', dispose: true }, this);
        if (!readResult) {
            this.working = false;
            return;
        }
        const fileName = FileUtils.getFileName(path);
        this.certificateFile = {
            fileName,
            contents: readResult,
        };
        this.working = false;
    }
    async selectKeyFLow() {
        this.working = true;
        const options = {
            multiple: false,
            title: 'Select a key file',
            filters: [{
                    description: 'Certificate key files',
                    accept: {
                        'application/x-pem-file': ['.pem', '.crt', '.cer', '.key']
                    },
                }],
        };
        const pickResult = await Events.Filesystem.requestOpenFile(options, this);
        if (!pickResult || pickResult.canceled) {
            this.working = false;
            return;
        }
        const [path] = pickResult.filePath;
        const readResult = await Events.Filesystem.readFile(path, { returnType: 'buffer', dispose: true }, this);
        if (!readResult) {
            this.working = false;
            return;
        }
        const fileName = FileUtils.getFileName(path);
        this.keyFile = {
            fileName,
            contents: readResult,
        };
        this.working = false;
    }
    isValidDropTarget(dt) {
        const types = Array.from(dt.types);
        return types.includes('Files');
    }
    handleFileDragEnter(e) {
        const dt = e.dataTransfer;
        if (!this.isValidDropTarget(dt)) {
            return;
        }
        e.preventDefault();
        dt.dropEffect = 'copy';
        const node = e.currentTarget;
        node.classList.add('dragover');
    }
    handleFileDragLeave(e) {
        const dt = e.dataTransfer;
        if (!this.isValidDropTarget(dt)) {
            return;
        }
        e.preventDefault();
        dt.dropEffect = 'none';
        const node = e.currentTarget;
        node.classList.remove('dragover');
    }
    handleFileDragOver(e) {
        const dt = e.dataTransfer;
        if (!this.isValidDropTarget(dt)) {
            return;
        }
        e.preventDefault();
        const node = e.currentTarget;
        node.classList.add('dragover');
    }
    handleFileDrop(e) {
        const dt = e.dataTransfer;
        e.preventDefault();
        const node = e.currentTarget;
        node.classList.remove('dragover');
        const file = dt.files[0];
        if (!file) {
            return;
        }
        const { kind } = node.dataset;
        if (!kind) {
            return;
        }
        this.processDroppedFile(file, kind);
    }
    async processDroppedFile(file, kind) {
        this.working = true;
        const buff = await file.arrayBuffer();
        const fileName = FileUtils.getFileName(file.name);
        if (kind === 'certificate') {
            this.certificateFile = {
                fileName,
                contents: buff,
            };
        }
        else if (kind === 'key') {
            this.keyFile = {
                fileName,
                contents: buff,
            };
        }
        this.working = false;
    }
    handleCancel() {
        this.dispatchEvent(new Event('close'));
    }
    handleImport() {
        this.submit();
    }
    async submit() {
        const invalid = this.reportValidity();
        if (invalid) {
            return;
        }
        const { certificateFile, certificateName, certificatePassword, keyFile, keyPassword, space, folder } = this;
        if (!space) {
            throw new Error(`The workspace key is not set on the certificate import element.`);
        }
        const cert = this.importType === 'p12' ?
            Certificate.fromP12(certificateFile?.contents, certificateName, certificatePassword) :
            Certificate.fromPem(certificateFile?.contents, keyFile?.contents, certificateName, keyPassword);
        const file = CertificateFile.fromCertificate(cert, space);
        await Events.Store.File.create(file.toJSON(), cert.toJSON(), { parent: folder }, this);
        this.handleCancel();
    }
    reportValidity() {
        const inputs = Array.from(this.shadowRoot.querySelectorAll('ui-text-field'));
        let invalid = false;
        inputs.forEach((input) => {
            const inputResult = input.reportValidity();
            if (!inputResult) {
                invalid = true;
            }
        });
        if (!invalid) {
            if (!this.certificateFile) {
                invalid = true;
                SnackNotifications.notify(`Certificate file is required.`);
            }
            if (!invalid && this.hasKeyImport && !this.keyFile) {
                invalid = true;
                SnackNotifications.notify(`The key file is required.`);
            }
        }
        return invalid;
    }
    render() {
        return html `
    <div class="form">
      ${this.renderProgress()}
      ${this.renderViewToggle()}
      ${this.renderNameInput()}
      ${this.renderCertificateFile()}
      ${this.renderCertificatePasswordInput()}
      ${this.renderKeyFile()}
      ${this.renderKeyPasswordInput()}
      ${this.renderImportButton()}
    </div>
    `;
    }
    renderViewToggle() {
        const { importType } = this;
        return html `
    <div class="view-toggle">
      <ui-segmented-button-set @select="${this.handleViewSelection}">
        <ui-segmented-button 
          .selected="${importType === 'pem'}" 
          title="Import a certificate in PEM format" 
          data-value="pem"
        >PEM</ui-segmented-button>
        <ui-segmented-button 
          .selected="${importType === 'p12'}" 
          title="Import a bundled PFX or PKCS12 encoded private key and certificate" 
          data-value="p12"
        >PFX or PKCS12</ui-segmented-button>
      </ui-segmented-button-set>
    </div>
    `;
    }
    renderNameInput() {
        const { certificateName = '' } = this;
        return html `
    <div class="form-input">
      <ui-text-field
        required
        name="name"
        .value="${live(certificateName)}"
        label="Certificate name"
        @change="${this.handleNameChange}"
        invalidText="The name is required"
      ></ui-text-field>
    </div>
    `;
    }
    renderCertificateFile() {
        const { certificateFile } = this;
        return html `
    <div class="cert-file" data-kind="certificate" @dragenter="${this.handleFileDragEnter}" @dragleave="${this.handleFileDragLeave}" @dragover="${this.handleFileDragOver}" @drop="${this.handleFileDrop}">
      <p class="body-medium">Select or drop a certificate file here.</p>
      <ui-button type="tonal" @click="${this.handleSelectCertificate}">Select certificate file</ui-button>
      ${certificateFile ? html `<span class="cert-info body-medium">${certificateFile.fileName}</span>` : html `<span class="missing body-medium"><ui-icon role="presentation" icon="warning" class="missing-icon"></ui-icon>Certificate is not selected</span>`}
    </div>
    `;
    }
    renderCertificatePasswordInput() {
        const { certificatePassword = '' } = this;
        if (!this.hasCertificatePasswordInput) {
            return nothing;
        }
        return html `
    <div class="form-input">
      <ui-text-field
        name="certificatePassword"
        type="password"
        .value="${live(certificatePassword)}"
        label="Certificate password"
        @change="${this.handleCertificatePasswordChange}"
        supportingText="Optional password for the certificate"
      ></ui-text-field>
    </div>
    `;
    }
    renderKeyFile() {
        if (!this.hasKeyImport) {
            return nothing;
        }
        const { keyFile } = this;
        return html `
    <div class="cert-file" data-kind="key" @dragenter="${this.handleFileDragEnter}" @dragleave="${this.handleFileDragLeave}" @dragover="${this.handleFileDragOver}" @drop="${this.handleFileDrop}">
      <p class="body-medium">Select or drop a key file here.</p>
      <ui-button type="tonal" @click="${this.handleSelectKey}">Select key file</ui-button>
      ${keyFile ? html `<span class="cert-info body-medium">${keyFile.fileName}</span>` : html `<span class="missing body-medium"><ui-icon role="presentation" icon="warning" class="missing-icon"></ui-icon>Key is not selected</span>`}
    </div>
    `;
    }
    renderKeyPasswordInput() {
        if (!this.hasKeyImport) {
            return nothing;
        }
        const { keyPassword = '' } = this;
        return html `
    <div class="form-input">
      <ui-text-field
        name="keyPassword"
        type="password"
        .value="${live(keyPassword)}"
        label="Key password"
        @change="${this.handleKeyPasswordChange}"
        supportingText="Optional password for the key"
      ></ui-text-field>
    </div>
    `;
    }
    renderImportButton() {
        return html `
    <div class="form-action">
      <ui-button type="filled" @click="${this.handleImport}">Import</ui-button>
      <ui-button type="text" @click="${this.handleCancel}">Cancel</ui-button>
    </div>
    `;
    }
    renderProgress() {
        if (!this.working) {
            return nothing;
        }
        return html `<ui-progress indeterminate class="working"></ui-progress>`;
    }
}
__decorate([
    property({ type: String })
], CertificateAdd.prototype, "importType", void 0);
__decorate([
    property({ type: String })
], CertificateAdd.prototype, "folder", void 0);
__decorate([
    property({ type: String })
], CertificateAdd.prototype, "space", void 0);
__decorate([
    state()
], CertificateAdd.prototype, "working", void 0);
__decorate([
    state()
], CertificateAdd.prototype, "certificateFile", void 0);
__decorate([
    state()
], CertificateAdd.prototype, "keyFile", void 0);
//# sourceMappingURL=CertificateAdd.element.js.map