import { h, Host } from "@stencil/core";
import { createEnvelope, formatFullName, getTemplate, getOrganizationContacts, getRGBA, isValidEmail } from "@verdocs/js-sdk";
import { getRoleIndex, getRoleNames } from "../../../utils/Templates";
import { DefaultEndpoint } from "../../../utils/Environment";
import { VerdocsToast } from "../../../utils/Toast";
import { SDKError } from "../../../utils/errors";
import { Store } from "../../../utils/Datastore";
const editIcon = '<svg focusable="false" aria-hidden="true" viewBox="0 0 24 24" tabindex="-1"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.9959.9959 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path></svg>';
const startIcon = '<svg focusable="false" aria-hidden="true" viewBox="0 0 24 24" tabindex="-1"><path d="M2 12C2 6.48 6.48 2 12 2s10 4.48 10 10-4.48 10-10 10S2 17.52 2 12zm10 6c3.31 0 6-2.69 6-6s-2.69-6-6-6-6 2.69-6 6 2.69 6 6 6z"></path></svg>';
const stepIcon = '<svg focusable="false" aria-hidden="true" viewBox="0 0 24 24" tabindex="-1"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"></path></svg>';
const doneIcon = '<svg focusable="false" aria-hidden="true" viewBox="0 0 24 24" tabindex="-1"><path d="m18 7-1.41-1.41-6.34 6.34 1.41 1.41L18 7zm4.24-1.41L11.66 16.17 7.48 12l-1.41 1.41L11.66 19l12-12-1.42-1.41zM.41 13.41 6 19l1.41-1.41L1.83 12 .41 13.41z"></path></svg>';
/**
 * Display a form to send a template to one or more recipients in an envelope for signing.
 * Host applications should ensure the template is "sendable" before displaying this component.
 * To be sendable, a template must have at least one document attached, at least one participant
 * defined, and at least one field assigned to every "signer" participant. This component will
 * hide itself if the template is not sendable.
 *
 * ```ts
 * <verdocs-send
 *   templateId={TEMPLATE_ID}
 *   onBeforeSend={({ detail })) => { console.log('Sending... Show a spinner...', detail) }
 *   onSend={({ detail }) => { console.log('Sent! Hide the spinner...', detail) }
 *   onExit={({ detail }) => { console.log('Send cancelled.', detail) }
 *   onSdkError={({ detail }) => { console.log('SDK error', detail) }
 *   />
 * ```
 */
export class VerdocsSend {
    constructor() {
        this.templateListenerId = null;
        /**
         * The endpoint to use to communicate with Verdocs. If not set, the default endpoint will be used.
         */
        this.endpoint = DefaultEndpoint;
        /**
         * The ID of the template to create the document from.
         */
        this.templateId = null;
        /**
         * The environment the control is being called from, e.g. 'web'. This has an impact on how certain
         * operations such as email communications are handled to ensure users receive the correct URLs for
         * their invitations. Setting this to unknown values may produce unexpected/incorrect behaviors.
         * If environment is not known, do this set this property.
         */
        this.environment = '';
        this.containerId = `verdocs-send-${Math.random().toString(36).substring(2, 11)}`;
        this.showPickerForId = '';
        this.sessionContacts = [];
        this.sending = false;
        this.rolesCompleted = {};
        this.loading = true;
        this.template = null;
    }
    disconnectedCallback() {
        this.unlistenToTemplate();
    }
    async listenToTemplate() {
        console.log('[SEND] Loading template', this.templateId);
        this.unlistenToTemplate();
        Store.subscribe('templates', this.templateId, () => getTemplate(this.endpoint, this.templateId), true, (template) => {
            console.log('[SEND] Got new template', template);
            this.template = template;
            this.loading = false;
            this.rolesCompleted = {};
            this.recomputeRolesCompleted();
        });
    }
    unlistenToTemplate() {
        if (this.templateListenerId) {
            Store.store.delListener(this.templateListenerId);
            this.templateListenerId = null;
        }
    }
    async reset() {
        this.rolesCompleted = {};
    }
    onTemplateIdChanged(newTemplateId) {
        console.log('[SEND] Template ID changed', newTemplateId);
        this.listenToTemplate();
    }
    async componentWillLoad() {
        var _a, _b, _c;
        try {
            this.endpoint.onSessionChanged((_endpoint, _session, profile) => {
                if (!profile) {
                    return;
                }
                const me = {
                    id: profile.id,
                    first_name: profile.first_name,
                    last_name: profile.last_name,
                    email: profile.email,
                    phone: profile.phone,
                };
                if (profile) {
                    this.sessionContacts = [me];
                    getOrganizationContacts(this.endpoint)
                        .then(contacts => {
                        console.log('[SEND] Got contacts', contacts);
                        this.sessionContacts = [...contacts, me];
                    })
                        .catch(e => {
                        console.log('[SEND] Error getting contacts', e);
                    });
                }
            });
            this.endpoint.loadSession();
            if (!this.endpoint.session) {
                console.log('[SEND] Unable to start Send operation, must be authenticated');
                return;
            }
            if (!this.templateId) {
                console.log(`[SEND] Missing required template ID ${this.templateId}`);
                return;
            }
            this.listenToTemplate();
        }
        catch (e) {
            console.log('[SEND] Error with send session', e);
            (_a = this.sdkError) === null || _a === void 0 ? void 0 : _a.emit(new SDKError(e.message, (_b = e.response) === null || _b === void 0 ? void 0 : _b.status, (_c = e.response) === null || _c === void 0 ? void 0 : _c.data));
        }
    }
    recomputeRolesCompleted() {
        var _a;
        this.rolesCompleted = {};
        const rolesAtLevel = {};
        (((_a = this.template) === null || _a === void 0 ? void 0 : _a.roles) || []).forEach(role => {
            const level = role.sequence;
            rolesAtLevel[level] || (rolesAtLevel[level] = []);
            const id = `r-${level}-${rolesAtLevel[level].length}`;
            rolesAtLevel[level].push({ ...role, id, role_name: role.name, first_name: role.first_name, last_name: role.last_name });
            // if (role.first_name && (isValidEmail(role.email) || isValidPhone(role.phone))) {
            if (role.first_name && isValidEmail(role.email)) {
                this.rolesCompleted[id] = { ...role, id, role_name: role.name, first_name: role.first_name, last_name: role.last_name };
            }
        });
    }
    getSequenceNumbers() {
        var _a;
        // This is cleaner with a Set but we found a regression in some target environments where
        // this breaks down. Reverting to an older technique while we diagnose it.
        const sequences = {};
        (((_a = this.template) === null || _a === void 0 ? void 0 : _a.roles) || []).forEach(role => {
            sequences[role.sequence] = true;
        });
        return Object.keys(sequences)
            .map(s => +s)
            .sort((a, b) => a - b);
    }
    getRolesAtLevel(level) {
        var _a;
        const rolesAtLevel = (((_a = this.template) === null || _a === void 0 ? void 0 : _a.roles) || [])
            .filter(role => role.sequence === level)
            .map((role, index) => ({
            ...role,
            id: `r-${level}-${index}`,
            role_name: role.name,
            first_name: role.first_name,
            last_name: role.last_name,
        }));
        return rolesAtLevel;
    }
    getLevelIcon(level) {
        if (level === 'start') {
            return h("div", { class: "level-icon", innerHTML: startIcon });
        }
        else if (level === 'end') {
            return h("div", { class: "level-icon", innerHTML: doneIcon });
        }
        else {
            return h("div", { class: "level-icon", innerHTML: stepIcon });
        }
    }
    handleSelectContact(e, role) {
        e.preventDefault();
        this.rolesCompleted[role.id] = { ...role, ...e.detail };
        this.showPickerForId = '';
    }
    handleClickRole(e, role) {
        e.stopPropagation();
        this.showPickerForId = role.id;
    }
    handleSend(e) {
        var _a;
        if (this.sending) {
            console.log('[SEND] Skipping duplicate send', e);
            return;
        }
        console.log('[SEND] Sending', e);
        e.preventDefault();
        e.stopPropagation();
        this.sending = true;
        const details = {
            template_id: this.templateId,
            name: ((_a = this.template) === null || _a === void 0 ? void 0 : _a.name) || 'New Envelope',
            environment: this.environment,
            initial_reminder: 0,
            followup_reminders: 0,
            recipients: Object.values(this.rolesCompleted),
            // TODO: Pre-filled fields support
            fields: [],
        };
        const beforeSendResult = this.beforeSend.emit({ ...details, name: details.name, template: this.template });
        if (beforeSendResult.defaultPrevented) {
            console.log('[SEND] Send cancelled by parent', details);
            this.sending = false;
            return;
        }
        console.log('[SEND] Creating envelope', details);
        createEnvelope(this.endpoint, details)
            .then(r => {
            var _a;
            console.log('[SEND] Send envelope', r);
            this.reset().catch((e) => console.log('Unknown Error', e));
            this.sending = false;
            (_a = this.send) === null || _a === void 0 ? void 0 : _a.emit({ ...details, name: details.name, envelope_id: r.id, envelope: r });
        })
            .catch(e => {
            var _a, _b, _c;
            console.log('[SEND] Send error', e);
            VerdocsToast(((_b = (_a = e.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.error) || 'Error creating envelope, please try again later.');
            this.sending = false;
            (_c = this.sdkError) === null || _c === void 0 ? void 0 : _c.emit(e);
        });
    }
    handleCancel(e) {
        var _a;
        e.stopPropagation();
        (_a = this.exit) === null || _a === void 0 ? void 0 : _a.emit();
    }
    render() {
        var _a;
        if (this.loading) {
            return (h(Host, null, h("verdocs-loader", null)));
        }
        if (!this.endpoint.session) {
            return (h(Host, { style: { display: 'flex' } }, h("verdocs-component-error", { message: "You must be authenticated to use this module." })));
        }
        const levels = this.getSequenceNumbers();
        const rolesAssigned = Object.values(this.rolesCompleted).filter(recipient => isValidEmail(recipient.email) && recipient.first_name && recipient.last_name);
        const allRolesAssigned = rolesAssigned.length >= getRoleNames(this.template).length;
        return (h(Host, { class: { sendable: (_a = this.template) === null || _a === void 0 ? void 0 : _a.is_sendable } }, h("div", { class: "recipients" }, h("div", { class: "left-line" }), h("div", { class: `level level-start` }, this.getLevelIcon('start'), h("div", { class: "complete" }, "Send Envelope")), levels.map(level => (h("div", { class: `level level-${level}` }, this.getLevelIcon('sequence'), this.getRolesAtLevel(level).map(role => {
            var _a, _b, _c;
            const unknown = !role.email || !role.first_name || !role.last_name;
            const roleName = ((_a = this.rolesCompleted[role.id]) === null || _a === void 0 ? void 0 : _a.first_name) ? formatFullName(this.rolesCompleted[role.id]) : unknown ? role.role_name : formatFullName(role);
            const elId = `verdocs-send-recipient-${role.role_name}`;
            const roleIndex = getRoleIndex(this.template, role.role_name);
            const rgba = getRGBA(roleIndex);
            const completed = rolesAssigned.findIndex(r => r.role_name === role.role_name) > -1;
            const style = {
                backgroundColor: rgba,
                border: completed ? '2px solid #55bc81' : '2px solid #dddddd',
            };
            return unknown ? (h("div", { class: "recipient", "data-ri": roleIndex, "data-rn": role.role_name, style: style, onClick: e => this.handleClickRole(e, role), id: elId }, roleName, h("div", { class: "icon", innerHTML: editIcon }), this.showPickerForId === role.id && (h("verdocs-portal", { anchor: elId, onClickAway: () => (this.showPickerForId = '') }, h("verdocs-contact-picker", { onExit: () => (this.showPickerForId = ''), onNext: e => this.handleSelectContact(e, role), contactSuggestions: this.sessionContacts, templateRole: (_b = this.rolesCompleted[role.id]) !== null && _b !== void 0 ? _b : role, onSearchContacts: e => { var _a; return (_a = this.searchContacts) === null || _a === void 0 ? void 0 : _a.emit(e.detail); } }))))) : (h("div", { class: "recipient", "data-ri": roleIndex, "data-rn": role.role_name, style: style, onClick: e => this.handleClickRole(e, role), id: elId }, roleName, h("div", { class: "icon", innerHTML: editIcon }), this.showPickerForId === role.id && (h("verdocs-portal", { anchor: elId, onClickAway: () => (this.showPickerForId = '') }, h("verdocs-contact-picker", { onExit: () => (this.showPickerForId = ''), onNext: e => this.handleSelectContact(e, role), contactSuggestions: this.sessionContacts, templateRole: ((_c = this.rolesCompleted[role.id]) !== null && _c !== void 0 ? _c : role), onSearchContacts: e => { var _a; return (_a = this.searchContacts) === null || _a === void 0 ? void 0 : _a.emit(e.detail); } })))));
        })))), h("div", { class: `level level-done` }, this.getLevelIcon('end'), h("div", { class: "complete" }, "Signing Complete"))), h("div", { class: "buttons" }, h("verdocs-button", { label: "Cancel", size: "small", variant: "outline", onClick: e => this.handleCancel(e), disabled: this.sending }), h("verdocs-button", { label: "Send", size: "small", disabled: !allRolesAssigned || this.sending, onClick: e => this.handleSend(e) }), this.sending && h("verdocs-spinner", null))));
    }
    static get is() { return "verdocs-send"; }
    static get originalStyleUrls() {
        return {
            "$": ["verdocs-send.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["verdocs-send.css"]
        };
    }
    static get properties() {
        return {
            "endpoint": {
                "type": "unknown",
                "attribute": "endpoint",
                "mutable": false,
                "complexType": {
                    "original": "VerdocsEndpoint",
                    "resolved": "VerdocsEndpoint",
                    "references": {
                        "VerdocsEndpoint": {
                            "location": "import",
                            "path": "@verdocs/js-sdk",
                            "id": "node_modules::VerdocsEndpoint"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The endpoint to use to communicate with Verdocs. If not set, the default endpoint will be used."
                },
                "getter": false,
                "setter": false,
                "defaultValue": "DefaultEndpoint"
            },
            "templateId": {
                "type": "string",
                "attribute": "template-id",
                "mutable": false,
                "complexType": {
                    "original": "string | null",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The ID of the template to create the document from."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "null"
            },
            "environment": {
                "type": "string",
                "attribute": "environment",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The environment the control is being called from, e.g. 'web'. This has an impact on how certain\noperations such as email communications are handled to ensure users receive the correct URLs for\ntheir invitations. Setting this to unknown values may produce unexpected/incorrect behaviors.\nIf environment is not known, do this set this property."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "''"
            }
        };
    }
    static get states() {
        return {
            "containerId": {},
            "showPickerForId": {},
            "sessionContacts": {},
            "sending": {},
            "rolesCompleted": {},
            "loading": {},
            "template": {}
        };
    }
    static get events() {
        return [{
                "method": "beforeSend",
                "name": "beforeSend",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "The user is sending an envelope the form and clicked send."
                },
                "complexType": {
                    "original": "{recipients: ICreateEnvelopeRecipient[]; name: string; template_id: string; template: ITemplate}",
                    "resolved": "{ recipients: ICreateEnvelopeRecipient[]; name: string; template_id: string; template: ITemplate; }",
                    "references": {
                        "ICreateEnvelopeRecipient": {
                            "location": "import",
                            "path": "@verdocs/js-sdk",
                            "id": "node_modules::ICreateEnvelopeRecipient"
                        },
                        "ITemplate": {
                            "location": "import",
                            "path": "@verdocs/js-sdk",
                            "id": "node_modules::ITemplate"
                        }
                    }
                }
            }, {
                "method": "send",
                "name": "send",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "The user completed the form and clicked send."
                },
                "complexType": {
                    "original": "{recipients: ICreateEnvelopeRecipient[]; name: string; template_id: string; envelope_id: string; envelope: IEnvelope}",
                    "resolved": "{ recipients: ICreateEnvelopeRecipient[]; name: string; template_id: string; envelope_id: string; envelope: IEnvelope; }",
                    "references": {
                        "ICreateEnvelopeRecipient": {
                            "location": "import",
                            "path": "@verdocs/js-sdk",
                            "id": "node_modules::ICreateEnvelopeRecipient"
                        },
                        "IEnvelope": {
                            "location": "import",
                            "path": "@verdocs/js-sdk",
                            "id": "node_modules::IEnvelope"
                        }
                    }
                }
            }, {
                "method": "exit",
                "name": "exit",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Event fired when the step is cancelled. This is called exit to avoid conflicts with the JS-reserved \"cancel\" event name."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "sdkError",
                "name": "sdkError",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Event fired if an error occurs. The event details will contain information about the error. Most errors will\nterminate the process, and the calling application should correct the condition and re-render the component."
                },
                "complexType": {
                    "original": "SDKError",
                    "resolved": "SDKError",
                    "references": {
                        "SDKError": {
                            "location": "import",
                            "path": "../../../utils/errors",
                            "id": "src/utils/errors.ts::SDKError"
                        }
                    }
                }
            }, {
                "method": "searchContacts",
                "name": "searchContacts",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Event fired when the user enters text in a search field. The parent application may use this to update\nthe `contactSuggestions` property."
                },
                "complexType": {
                    "original": "IContactSearchEvent",
                    "resolved": "IContactSearchEvent",
                    "references": {
                        "IContactSearchEvent": {
                            "location": "import",
                            "path": "../../envelopes/verdocs-contact-picker/verdocs-contact-picker",
                            "id": "src/components/envelopes/verdocs-contact-picker/verdocs-contact-picker.tsx::IContactSearchEvent"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "reset": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": []
                }
            }
        };
    }
    static get watchers() {
        return [{
                "propName": "templateId",
                "methodName": "onTemplateIdChanged"
            }];
    }
}
//# sourceMappingURL=verdocs-send.js.map
