import type { IWebApiClient, WebClientApiMethod } from '../../common/IWebClient';
import type { DataTableExportConfig, TableColumn } from './datatable';
import { toNative } from 'vue-facing-decorator';
import PowerduckState from '../../app/powerduck-state';
import TsxComponent, { Component } from '../../app/vuetsx';
import { ExcelJsProvider } from '../../common/excel/excel-js-provider';
import { PortalUtils } from '../../common/utils/utils';
import LoadingIndicator from '../loading-indicator';
import Modal from '../modal/modal';
import ModalBody from '../modal/modal-body';
import NotificationProvider from '../ui/notification';

interface TableExportModalBindingArgs { }

interface TableExportModalArgs {
	columns: TableColumn[];
	rows: any[];
	apiClient: IWebApiClient;
	apiMethod: WebClientApiMethod;
	apiArgs?: any;
	exportConfig: DataTableExportConfig;
	paginationOffset?: number;
	paginationLength: number;
	totalFilteredCount: number;
}

const enum TableExportPhase {
	RecordsetSelection = 0,
	Loading = 1,
}

@Component
class TableExportModalComponent extends TsxComponent<TableExportModalBindingArgs> implements TableExportModalBindingArgs {
	columns: TableColumn[] = null;
	phase: TableExportPhase = null;
	rows: any[] = null;
	excelJsLoaded: boolean = false;
	dataLoaded: boolean = false;
	totalFilteredCount: number = null;
	downloadedCount: number = null;

	show(args: TableExportModalArgs) {
		this.columns = args.columns;
		this.rows = args.rows;
		this.phase = TableExportPhase.RecordsetSelection;
		this.excelJsLoaded = ExcelJsProvider.excelJsInstance() != null;
		this.dataLoaded = (this.rows || []).length >= args.totalFilteredCount;
		this.totalFilteredCount = args.totalFilteredCount;
		(this.$refs.tableExportDialog as typeof Modal.prototype).show();

		if (!this.excelJsLoaded) {
			ExcelJsProvider.getExcelJs().then((excelJs) => {
				this.excelJsLoaded = true;
				this.exportExcel();
			}).catch((err) => {
				NotificationProvider.showErrorMessage(err);
				this.hideExportModal();
			});
		}

		if (!this.dataLoaded) {
			this.rows = [];
			this.downloadedCount = 0;
			this.downloadDataChunk(
				args.apiClient,
				args.apiMethod,
				args.apiArgs,
				0,
				args.paginationLength,
				args.exportConfig,
			);
			this.exportExcel();
		}

		this.exportExcel();
	}

	downloadDataChunk(
		apiClient: IWebApiClient,
		apiMethod: WebClientApiMethod,
		ajaxArgs: any,
		steps: number,
		paginationLength: number,
		exportConfig?: DataTableExportConfig,
	): void {
		const STEP_COUNT = 1000;
		ajaxArgs.PaginationPosition = steps + 1;
		ajaxArgs.PaginationLength = STEP_COUNT;

		if (exportConfig != null) {
			if (exportConfig.limitName != null) {
				ajaxArgs[exportConfig.limitName] = STEP_COUNT;
			}

			if (exportConfig.pageName != null) {
				ajaxArgs[exportConfig.pageName] = steps + 1;
			}
		}

		apiClient[apiMethod](ajaxArgs).then((data: any) => {
			const attrName = exportConfig != null && exportConfig.attrName != null ? exportConfig.attrName : 'Rows';
			const rows = data[attrName];

			rows.forEach((row) => {
				this.rows.push(row);
			});

			this.downloadedCount += rows.length;
			if (rows.length < STEP_COUNT) {
				this.totalFilteredCount = this.downloadedCount;
				this.dataLoaded = true;
				this.exportExcel();
			} else {
				this.downloadDataChunk(
					apiClient,
					apiMethod,
					ajaxArgs,
					steps + 1,
					paginationLength,
					exportConfig,
				);
			}
		}).catch(() => {
			NotificationProvider.showErrorMessage(PowerduckState.getResourceValue('errorFetchingData'));
			this.hideExportModal();
		});
	}

	hideExportModal() {
		(this.$refs.tableExportDialog as typeof Modal.prototype).hide();
	}

	exportExcel() {
		if (this.dataLoaded && this.excelJsLoaded) {
			const colArr = [];
			this.columns.forEach((item) => {
				if (item.exportInclude != false) {
					colArr.push({
						header: item.caption,
						width: 25,
					});
				}
			});

			const workbook = new (ExcelJsProvider.excelJsInstance()).Workbook();
			// eslint-disable-next-line no-restricted-syntax
			workbook.created = new Date();
			// eslint-disable-next-line no-restricted-syntax
			workbook.modified = new Date();
			// eslint-disable-next-line no-restricted-syntax
			workbook.lastPrinted = new Date();

			const worksheet = workbook.addWorksheet('Export');
			worksheet.columns = colArr;
			worksheet.views = [{ state: 'frozen', xSplit: 0, ySplit: 1 }];

			const firstRow = worksheet.getRow(1);
			firstRow.font = { name: 'Arial', family: 4, size: 10, bold: true, color: { argb: '00000000' }, bgColor: { argb: '80EF1C1C' } };
			firstRow.alignment = { vertical: 'middle', horizontal: 'center' };
			firstRow.height = 20;
			firstRow._cells.forEach((cell) => {
				cell.fill = {
					type: 'pattern',
					pattern: 'solid',
					fgColor: { argb: 'cccccc' },
				};
			});

			this.rows.forEach((row) => {
				const rowExportData = [];

				this.columns.forEach((col) => {
					if (col.exportInclude != false) {
						if (col.exportValue != null) {
							rowExportData.push(col.exportValue(row));
						} else if (col.customValue != null) {
							rowExportData.push(col.customValue(row));
						} else {
							rowExportData.push(row[col.id]);
						}
					}
				});

			    const addedRow = worksheet.addRow(rowExportData);

                addedRow.eachCell((cell) => {
                    if (cell.value instanceof Date) {
                        cell.numFmt = 'dd/mm/yyyy hh:mm:ss';
                    }
                });
			});

			workbook.xlsx.writeBuffer().then((data: any) => {
				const blob = new Blob([data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
				PortalUtils.downloadBlob(
					blob,
					'export.xlsx',
					() => {
						setTimeout(() => {
							this.hideExportModal();
						}, 300);
					},
				);
			}).catch((err) => {
				console.error(err);
			});
		}
	}

	getCompletePercent() {
		return `${Math.round((this.downloadedCount / this.totalFilteredCount) * 100)} %`;
	}

	render(h) {
		return (
			<Modal ref="tableExportDialog" title="Export">
				<ModalBody>
					<div style="min-height:200px;position:relative;">
						<LoadingIndicator visible={true} />
					</div>
					<h4 style="text-align:center;">
						{this.getCompletePercent()}
					</h4>
				</ModalBody>
			</Modal>
		);
	}
}

const TableExportModal = toNative(TableExportModalComponent);
export default TableExportModal;
