import { h } from "@stencil/core";
import { ComponentErrorCodes, ComponentErrorSeverity, EntityDocument, } from "../../../../api";
import { makeGetBusiness, makePostDocumentRecord } from "../payment-provisioning-actions";
import { BusinessService, DocumentRecordService } from "../../../../api/services/business.service";
import { CountryCode } from "../../../../utils/country-codes";
import { BusinessFormStep } from "../../utils";
import { heading2 } from "../../../../styles/parts";
import { PaymentProvisioningLoading } from "../payment-provisioning-loading";
import { buildAllCategories, personalDocGroup1Types, personalDocGroup2Types, } from "./document-upload-options";
export class DocumentUploadFormStep {
    constructor() {
        this.owners = [];
        this.existingDocuments = [];
        this.selectedCategory = '';
        this.selectedDocType = '';
        this.uploadQueue = [];
        this.isLoading = false;
        this.errors = {};
        this.fileInputKey = 0;
        this.categories = [];
        this.getData = () => {
            this.isLoading = true;
            this.getBusiness({
                onSuccess: (response) => {
                    const { owners, documents } = response.data;
                    this.owners = owners || [];
                    this.existingDocuments = documents || [];
                    this.categories = buildAllCategories(this.country);
                },
                onError: ({ error, code, severity }) => {
                    this.errorEvent.emit({
                        message: error,
                        errorCode: code,
                        severity: severity,
                    });
                },
                final: () => {
                    this.isLoading = false;
                }
            });
        };
        this.handleCategoryChange = (_name, value) => {
            this.selectedCategory = value;
            this.selectedDocType = '';
        };
        this.handleDocTypeChange = (_name, value) => {
            if (value.startsWith('_') && value.endsWith('_header'))
                return;
            this.selectedDocType = value;
        };
        this.handleFileSelected = async (e) => {
            const fileList = Array.from(e.detail.fileList);
            const category = this.categories.find(c => c.value === this.selectedCategory);
            if (!category)
                return;
            const docTypeOption = category.docTypeOptions.find(o => o.value === this.selectedDocType);
            const docTypeLabel = (docTypeOption === null || docTypeOption === void 0 ? void 0 : docTypeOption.label) || this.selectedDocType;
            const newEntries = fileList.map(file => ({
                categoryLabel: category.label,
                categoryValue: category.value,
                docTypeLabel,
                docTypeValue: this.selectedDocType,
                fileName: file.name,
                file,
                status: 'uploading',
            }));
            const startIndex = this.uploadQueue.length;
            this.uploadQueue = [...this.uploadQueue, ...newEntries];
            this.selectedCategory = '';
            this.selectedDocType = '';
            this.fileInputKey++;
            await Promise.all(newEntries.map(async (entry, i) => {
                const index = startIndex + i;
                try {
                    const docData = new EntityDocument({ file: entry.file, document_type: entry.docTypeValue }, this.businessId);
                    const recordCreated = await this.postDocumentRecordData(docData);
                    if (!recordCreated) {
                        this.uploadQueue = this.uploadQueue.map((e, j) => j === index ? Object.assign(Object.assign({}, e), { status: 'error' }) : e);
                        return;
                    }
                    const uploaded = await this.uploadDocument(docData);
                    this.uploadQueue = this.uploadQueue.map((e, j) => j === index ? Object.assign(Object.assign({}, e), { status: uploaded ? 'uploaded' : 'error' }) : e);
                }
                catch (_a) {
                    this.uploadQueue = this.uploadQueue.map((e, j) => j === index ? Object.assign(Object.assign({}, e), { status: 'error' }) : e);
                }
            }));
        };
        this.postDocumentRecordData = async (docData) => {
            const payload = docData.record_data;
            return new Promise((resolve) => {
                this.postDocumentRecord({
                    payload,
                    onSuccess: (response) => {
                        resolve(this.handleDocRecordResponse(docData, response));
                    },
                    onError: ({ error, code, severity }) => {
                        this.errorEvent.emit({
                            message: error,
                            errorCode: code,
                            severity: severity,
                        });
                        resolve(false);
                    },
                });
            });
        };
        this.handleDocRecordResponse = (docData, response) => {
            if (response.error) {
                this.errorEvent.emit({
                    errorCode: ComponentErrorCodes.POST_ERROR,
                    message: response.error.message,
                    severity: ComponentErrorSeverity.ERROR,
                    data: response.error,
                });
                return false;
            }
            else {
                docData.setPresignedUrl(response.data.presigned_url);
                return true;
            }
        };
        this.uploadDocument = async (docData) => {
            if (!docData.presigned_url) {
                throw new Error('Presigned URL is not set');
            }
            const fileData = await docData.getFileData();
            const response = await fetch(docData.presigned_url, {
                method: 'PUT',
                body: fileData,
            });
            if (!response.ok) {
                this.errorEvent.emit({
                    errorCode: ComponentErrorCodes.POST_ERROR,
                    message: 'Failed to upload document',
                    severity: ComponentErrorSeverity.ERROR,
                });
                return false;
            }
            return true;
        };
    }
    propChanged() {
        this.initializeApi();
    }
    watchHandler(newValue) {
        this.formLoading.emit(newValue);
    }
    async validateAndSubmit({ onSuccess }) {
        const validationErrors = this.validate();
        if (Object.keys(validationErrors).length > 0) {
            this.errors = validationErrors;
            return;
        }
        this.errors = {};
        this.stepCompleteEvent.emit({ response: null, formStep: BusinessFormStep.documentUpload });
        onSuccess();
    }
    componentWillLoad() {
        this.initializeApi();
        if (this.getBusiness) {
            this.getData();
        }
    }
    initializeApi() {
        if (this.authToken && this.businessId) {
            this.getBusiness = makeGetBusiness({
                authToken: this.authToken,
                businessId: this.businessId,
                service: new BusinessService()
            });
            this.postDocumentRecord = makePostDocumentRecord({
                authToken: this.authToken,
                service: new DocumentRecordService()
            });
        }
        else {
            this.errorEvent.emit({
                message: 'Missing required props',
                errorCode: ComponentErrorCodes.MISSING_PROPS,
                severity: ComponentErrorSeverity.ERROR,
            });
        }
    }
    get categoryOptions() {
        return [
            { label: 'Select a category', value: '' },
            ...this.categories.map(c => ({ label: c.label, value: c.value })),
        ];
    }
    get docTypeOptions() {
        if (!this.selectedCategory) {
            return [{ label: 'Select a category first', value: '' }];
        }
        const category = this.categories.find(c => c.value === this.selectedCategory);
        return (category === null || category === void 0 ? void 0 : category.docTypeOptions) || [{ label: 'Select a category first', value: '' }];
    }
    validate() {
        if (this.allowOptionalFields)
            return {};
        const errors = {};
        const financialDocTypes = ['voided_check', 'bank_statement'];
        const hasExistingDoc = (types) => this.existingDocuments.some(doc => types.includes(doc.document_type));
        const hasUploadedDoc = (categoryValue) => this.uploadQueue.some(entry => entry.categoryValue === categoryValue && entry.status === 'uploaded');
        if (!hasUploadedDoc('financial_document') && !hasExistingDoc(financialDocTypes)) {
            errors['financial_document'] = 'Please upload a financial document';
        }
        if (this.country === CountryCode.CAN) {
            const businessDocTypes = ['articles_of_incorporation', 'business_registration'];
            if (!hasUploadedDoc('business_document') && !hasExistingDoc(businessDocTypes)) {
                errors['business_document'] = 'Please upload a business document';
            }
            const requiredCount = this.owners.length;
            const group1Uploaded = this.uploadQueue.filter(entry => entry.categoryValue === 'personal_group1' && entry.status === 'uploaded').length;
            const group1Existing = this.existingDocuments.filter(doc => personalDocGroup1Types.has(doc.document_type)).length;
            if (group1Uploaded + group1Existing < requiredCount) {
                errors['personal_group1'] =
                    `Please upload ${requiredCount} Group 1 identity document(s) (${group1Uploaded + group1Existing} of ${requiredCount} provided)`;
            }
            const group2Uploaded = this.uploadQueue.filter(entry => entry.categoryValue === 'personal_group2' && entry.status === 'uploaded').length;
            const group2Existing = this.existingDocuments.filter(doc => personalDocGroup2Types.has(doc.document_type)).length;
            if (group2Uploaded + group2Existing < requiredCount) {
                errors['personal_group2'] =
                    `Please upload ${requiredCount} Group 2 identity document(s) (${group2Uploaded + group2Existing} of ${requiredCount} provided)`;
            }
        }
        return errors;
    }
    render() {
        if (this.isLoading) {
            return h(PaymentProvisioningLoading, null);
        }
        return (h("form", null, h("fieldset", null, h("legend", { class: "mb-0", part: heading2 }, "Document Uploads"), h("hr", { class: "mt-2" }), h("business-documents-on-file", { documents: this.existingDocuments, isLoading: this.isLoading })), this.country === CountryCode.CAN && this.owners.length > 0 && (h("div", { class: "alert alert-info mt-3" }, "One document from each group (Group 1 and Group 2) is required for each owner (", this.owners.length, " owner(s)).")), h("fieldset", { class: "mt-4" }, h("div", { class: "d-flex align-items-center gap-2" }, h("legend", { class: "mb-0", part: heading2 }, "Add Document"), h("form-control-tooltip", { helpText: "Upload documents one at a time. Select the category and type, then choose a file. For Canadian businesses, one Group 1 and one Group 2 identity document is required for each owner." })), h("hr", { class: "mt-2" }), h("div", { class: "row gy-3" }, h("div", { class: "col-12 col-md-6" }, h("form-control-select", { name: "document_category", label: "Document Category", options: this.categoryOptions, defaultValue: this.selectedCategory, inputHandler: this.handleCategoryChange })), h("div", { class: "col-12 col-md-6" }, h("form-control-select", { name: "document_type", label: "Document Type", options: this.docTypeOptions, defaultValue: this.selectedDocType, inputHandler: this.handleDocTypeChange, disabled: !this.selectedCategory })), h("div", { class: "col-12" }, h("form-control-file", { key: this.fileInputKey, name: "document_file", label: "Upload Document", documentType: this.selectedDocType, onFileSelected: this.handleFileSelected, disabled: !this.selectedDocType, multiple: false })))), h("document-upload-list", { documents: this.uploadQueue }), Object.keys(this.errors).length > 0 && (h("div", { class: "alert alert-danger mt-3" }, h("ul", { class: "mb-0" }, Object.values(this.errors).map(err => h("li", null, err)))))));
    }
    static get is() { return "document-upload-form-step"; }
    static get properties() {
        return {
            "authToken": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "auth-token"
            },
            "businessId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "business-id"
            },
            "allowOptionalFields": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "allow-optional-fields"
            },
            "country": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "CountryCode",
                    "resolved": "CountryCode.CAN | CountryCode.USA",
                    "references": {
                        "CountryCode": {
                            "location": "import",
                            "path": "../../../../utils/country-codes",
                            "id": "src/utils/country-codes.ts::CountryCode"
                        }
                    }
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "country"
            }
        };
    }
    static get states() {
        return {
            "owners": {},
            "existingDocuments": {},
            "selectedCategory": {},
            "selectedDocType": {},
            "uploadQueue": {},
            "isLoading": {},
            "errors": {},
            "fileInputKey": {},
            "getBusiness": {},
            "postDocumentRecord": {}
        };
    }
    static get events() {
        return [{
                "method": "errorEvent",
                "name": "error-event",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "ComponentErrorEvent",
                    "resolved": "ComponentErrorEvent",
                    "references": {
                        "ComponentErrorEvent": {
                            "location": "import",
                            "path": "../../../../api",
                            "id": "src/api/index.ts::ComponentErrorEvent"
                        }
                    }
                }
            }, {
                "method": "stepCompleteEvent",
                "name": "complete-form-step-event",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "ComponentFormStepCompleteEvent",
                    "resolved": "ComponentFormStepCompleteEvent",
                    "references": {
                        "ComponentFormStepCompleteEvent": {
                            "location": "import",
                            "path": "../../../../api",
                            "id": "src/api/index.ts::ComponentFormStepCompleteEvent"
                        }
                    }
                }
            }, {
                "method": "formLoading",
                "name": "formLoading",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": ""
                },
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                }
            }];
    }
    static get methods() {
        return {
            "validateAndSubmit": {
                "complexType": {
                    "signature": "({ onSuccess }: { onSuccess: any; }) => Promise<void>",
                    "parameters": [{
                            "name": "__0",
                            "type": "{ onSuccess: any; }",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": []
                }
            }
        };
    }
    static get watchers() {
        return [{
                "propName": "authToken",
                "methodName": "propChanged"
            }, {
                "propName": "businessId",
                "methodName": "propChanged"
            }, {
                "propName": "isLoading",
                "methodName": "watchHandler"
            }];
    }
}
