/***********************************************************************************
 * The contents of this file are subject to the Extension License Agreement
 * ("Agreement") which can be viewed at
 * https://www.espocrm.com/extension-license-agreement/.
 * By copying, installing downloading, or using this file, You have unconditionally
 * agreed to the terms and conditions of the Agreement, and You may not use this
 * file except in compliance with the Agreement. Under the terms of the Agreement,
 * You shall not license, sublicense, sell, resell, rent, lease, lend, distribute,
 * redistribute, market, publish, commercialize, or otherwise transfer rights or
 * usage to the software or any modified version or derivative work of the software
 * created by or for you.
 *
 * Copyright (C) 2015-2025 Letrium Ltd.
 *
 * License ID: e4c270586a0c8a9fda53bda910f357e0
 ************************************************************************************/

define(['advanced:views/report/reports/base'], (/** typeof BaseReportView */Dep) => {

    return class ListReportView extends Dep {

        setup() {
            this.initReport();
        }

        getListLayout(forExport) {
            const scope = this.model.get('entityType');
            const layout = [];

            const columnsData = Espo.Utils.cloneDeep(this.model.get('columnsData') || {});

            (this.model.get('columns') || []).forEach(item => {
                /** @type {Record.<string, *>} */
                const o = columnsData[item] || {};

                o.name = item;

                if (!forExport && o.exportOnly) {
                    return;
                }

                if (~item.indexOf('.')) {
                    const a = item.split('.');
                    o.name = item.replace('.', '_');
                    o.notSortable = true;

                    const link = a[0];
                    const field = a[1];

                    const foreignScope = this.getMetadata().get(`entityDefs.${scope}.links.${link}.entity`);

                    o.customLabel = this.translate(link, 'links', scope) + ' . ' +
                        this.translate(field, 'fields', foreignScope);

                    const type = this.getMetadata().get(`entityDefs.${foreignScope}.fields.${field}.type`);

                    // Warning. The same logic is in the report dashlet view.
                    if (type === 'enum') {
                        o.view = 'views/fields/foreign-enum';
                        o.options = {
                            params: {link, field},
                        };
                    } else if (type === 'image') {
                        o.view = 'views/fields/image';
                        o.options = {
                            foreignScope: foreignScope
                        };
                    } else if (type === 'file') {
                        o.view = 'views/fields/file';
                        o.options = {
                            foreignScope: foreignScope
                        };
                    } else if (type === 'date') {
                        o.view = 'views/fields/foreign-date';
                        o.notSortable = false;
                        o.options = {
                            params: {link, field},
                        };
                    } else if (type === 'datetime') {
                        o.view = 'views/fields/foreign-datetime';
                        o.options = {
                            params: {link, field},
                        };
                        o.notSortable = false;
                    } else if (type === 'link') {
                        o.view = 'advanced:views/fields/foreign-link';
                    } else if (type === 'email') {
                        o.view = 'views/fields/email';
                        o.notSortable = false;
                    } else if (type === 'phone') {
                        o.view = 'views/fields/phone';
                        o.notSortable = false;
                    } else if (type === 'array') {
                        o.view = 'views/fields/foreign-array';
                        o.options = {
                            params: {link, field},
                        };
                    } else if (type === 'multiEnum') {
                        o.view = 'views/fields/foreign-multi-enum';
                        o.options = {
                            params: {link, field},
                        };
                    } else if (type === 'checklist') {
                        o.view = 'views/fields/foreign-checklist';
                        o.options = {
                            params: {link, field},
                        };
                    } else if (type === 'urlMultiple') {
                        o.view = 'views/fields/foreign-url-multiple';
                        o.options = {
                            params: {link, field},
                        };
                    } else if (type === 'varchar') {
                        o.view = 'views/fields/varchar';
                        o.notSortable = false;
                    } else if (type === 'bool') {
                        o.view = 'views/fields/bool';
                        o.notSortable = false;
                    } else if (type === 'currencyConverted') {
                        o.view = 'views/fields/currency-converted';
                        o.notSortable = false;
                    }
                } else {
                    const type = this.getMetadata().get(['entityDefs', scope, 'fields', item, 'type']);

                    if (type === 'linkMultiple') {
                        o.notSortable = true;
                    } else if (type === 'attachmentMultiple') {
                        o.notSortable = true;
                    }
                }

                layout.push(o);
            });

            return layout;
        }

        export() {
            const where = this.getRuntimeFilters();

            const url = 'Report/action/exportList';

            const data = {
                id: this.model.id,
            };

            const fieldList = [];

            const listLayout = this.getListLayout(true);

            listLayout.forEach(item => {
                fieldList.push(item.name);
            });

            const o = {
                fieldList: fieldList,
                scope: this.model.get('entityType'),
            };

            this.createView('dialogExport', 'views/export/modals/export', o, (view) => {
                view.render();

                this.listenToOnce(view, 'proceed', (dialogData) => {
                    if (!dialogData.exportAllFields) {
                        data.attributeList = dialogData.attributeList;
                        data.fieldList = dialogData.fieldList;
                    }

                    data.where = where;
                    data.format = dialogData.format;
                    data.params = dialogData.params;

                    Espo.Ui.notify(' ... ');

                    Espo.Ajax.postRequest(url, data, {timeout: 0})
                        .then(data => {
                            Espo.Ui.notify(false);

                            if ('id' in data) {
                                window.location = this.getBasePath() + '?entryPoint=download&id=' + data.id;
                            }
                        });
                });
            });
        }

        prepareBeforeRun() {
            /** @type {HTMLElement} */
            this.resultContainerElement = this.element.querySelector('.report-results-container');

            const hasNoData = !!this.resultContainerElement.querySelector('.report-list .no-data');

            this.resultContainerElement.innerHTML = '';

            /** @type {HTMLElement} */
            this.listContainerElement = document.createElement('div');
            this.listContainerElement.classList.add('report-list');

            if (!hasNoData) {
                // To keep height on refresh.
                this.element.classList.add('no-bottom-margin');
                this.resultContainerElement.classList.add('no-bottom-margin');
                this.listContainerElement.classList.add('no-bottom-margin');
            }

            this.resultContainerElement.append(this.listContainerElement);
        }

        async run() {
            Espo.Ui.notify(' ... ')

            this.prepareBeforeRun();

            const collection = await this.getCollectionFactory().create(this.model.get('entityType'));

            let url = `Report/action/runList?id=${this.model.id}`;

            if (this.isPreview) {
                const dataPart = encodeURIComponent(JSON.stringify(this.model.attributes));

                url = 'Report/runListPreview?data=' + dataPart;
            }

            collection.url = url;
            collection.where = this.getRuntimeFilters();

            const orderByList = this.model.get('orderByList');

            if (orderByList) {
                const arr = orderByList.split(':');

                if (collection.setOrder) {
                    collection.setOrder(arr[1], arr[0] === 'ASC' ? 'asc' : 'desc', true);
                }
            }

            collection.maxSize = this.getConfig().get('recordsPerPage') || 20;

            this.listenToOnce(collection, 'sync', () => {
                this.storeRuntimeFilters();

                this.createView('list', 'advanced:views/record/list-for-report', {
                    selector: '.report-list',
                    collection: collection,
                    listLayout: this.getListLayout(),
                    displayTotalCount: true,
                    reportId: this.model.id,
                    runtimeWhere: collection.where,
                    pagination: this.options.isLargeMode,
                    isPreview: this.isPreview,
                }, async view => {
                    Espo.Ui.notify(false);

                    this.listenTo(view, 'after:render', () => {
                        view.$el.find('> .list')
                            .addClass('no-side-margin')
                            .addClass('no-bottom-margin')
                            .addClass('bottom-border-radius');

                        view.$el.find('.list-buttons-container').addClass('margin-bottom');
                    });

                    this.element.classList.remove('no-bottom-margin');
                    this.resultContainerElement.classList.remove('no-bottom-margin');
                    this.listContainerElement.classList.remove('no-bottom-margin');

                    await view.render();

                    const hasNoData = !!this.resultContainerElement.querySelector('.report-list .no-data');

                    if (!hasNoData) {
                        this.listContainerElement.classList.add('no-bottom-margin');
                    }
                });
            });

            return collection.fetch();
        }
    }
});
