import type { DropdownOptionGroup } from '../dropdown';
import { Component, Prop } from 'vue-facing-decorator';
import TsxComponent from '../../app/vuetsx';
import { isNullOrEmpty } from '../../common/utils/is-null-or-empty';
import BootstrapToggle from '../bootstrap-toggle';
import DropdownList from '../dropdown';
import HtmlLiteral from '../html-literal/html-literal';
import TextBox, { TextBoxTextType } from '../input/textbox';
import './css/import-mapper.css';
import { latinize } from '../../common/extensions/string-extensions';

export interface ImportMapperMapping {
	columnIndex: number;
	mappingValue: string;
}

interface ImportMapperArgs {
	cssClass?: string;
	subtitleHtml: string;
	mappingOptions: DropdownOptionGroup[];
	importData: Array<Array<string>>;
	firstRowIsHeaderLabel?: string;
	defaultMapping?: ImportMapperMapping[];
}

@Component
export default class ImportMapper extends TsxComponent<ImportMapperArgs> implements ImportMapperArgs {
	@Prop() cssClass!: string;
	@Prop() subtitleHtml!: string;
	@Prop() mappingOptions!: DropdownOptionGroup[];
	@Prop() importData!: Array<Array<string>>;
	@Prop() defaultMapping!: ImportMapperMapping[];
	@Prop() firstRowIsHeaderLabel!: string;
	private selectionMap: any = {};
	private firstRowHeader: boolean = false;
	private wasMatched = [];

	public getData(): any[] {
		const retVal = [];

		this.importData.forEach((row, i) => {
			if (!this.firstRowHeader || i > 0) {
				const newItem = {};
				for (const key in this.selectionMap) {
					const keyInt = Number(key);
					let objVal = row[keyInt];

					if (objVal != null) {
						if (typeof objVal === 'string') {
							objVal = objVal.trim();
						}
					}

					newItem[this.selectionMap[key]] = objVal;
				}

				retVal.push(newItem);
			}
		});

		return retVal;
	}

	private getDisplayValue(obj: any): string {
		if (obj == null) {
			return null;
		} else if (obj._dte) {
			return obj.toDisplayString(true);
		}

		return obj;
	}

	private getLargestRow(): string[] {
		if (isNullOrEmpty(this.importData)) {
			return [];
		}

		let biggestLength = 0;
		this.importData.forEach((rowArr) => {
			if (rowArr != null && rowArr.length > biggestLength) {
				biggestLength = rowArr.length;
			}
		});

		const retVal = [];
		while (true) {
			if (retVal.length < biggestLength) {
				retVal.push('x');
			} else {
				break;
			}
		}

		return retVal;
	}

	private getDropdownSelectedItem(index: number) {
		const selection = this.selectionMap[index];

		if (selection == null) {
			const match = this.getHeaderItem(index);

			if (!isNullOrEmpty(match) && !this.wasMatched.includes(index)) {
				this.wasMatched.push(index);
				this.setDropdownSelectedItem(index, match.id);
				return match.id;
			} else {
				return null;
			}
		}

		if (selection.includes('ncf:')) {
			return 'custom';
		}

		return this.selectionMap[index];
	}

	private setDropdownSelectedItem(index: number, value: any) {
		if (value == null || value.id == null) {
			if (typeof value === 'string') {
				// this.$set(this.selectionMap, index.toString(), value);
				this.selectionMap[index.toString()] = value;
			} else {
				// this.$set(this.selectionMap, index.toString(), null);
				this.selectionMap[index.toString()] = null;
			}
		} else {
			// this.$set(this.selectionMap, index.toString(), value.id);
			this.selectionMap[index.toString()] = value.id;
		}
	}

	private getPreviewRows(): Array<string[]> {
		if (isNullOrEmpty(this.importData)) {
			return [];
		}

		let start = 0;
		let end = 10;
		if (this.firstRowHeader) {
			start += 1;
			end += 1;
		}

		return this.importData.filter((u, i) => i >= start && i < end);
	}

	private getHeaderItem(index: number) {
		const opts = [];

		this.mappingOptions.forEach((mapOpts) => {
			mapOpts.children.forEach((s) => {
				opts.push(s);
			});
		});

		if (this.importData[0][index] != null) {
			const indexItem = this.importData[0][index].toString();
			const headers = opts.filter(p => p.text[latinize]().toLowerCase() == indexItem[latinize]().toLowerCase() || p.id[latinize]().toLowerCase() == indexItem[latinize]().toLowerCase());
			if (headers != null && headers.length == 1) {
				return headers[0];
			}
		} else {
			return null;
		}
	}

	private prefillNewCustomFieldName(index: number) {
		let retVal = '';
		if (this.selectionMap[index].includes('ncf:')) {
			retVal = this.selectionMap[index].substring(4);
		} else {
			retVal = this.importData[0][index];
		}

		this.setDropdownSelectedItem(index, `ncf:${retVal}`);
		return retVal;
	}

	private render(h) {
		const largestRow = this.getLargestRow();

		return (
			<div class="import-mapper-root">
				<p class="import-mapper-subtitle">
					<HtmlLiteral innerHTML={this.subtitleHtml} />
				</p>

				{this.importData
				&& (
					<div class="import-mapper-table-wrap">
						<table class="import-mapper-table">
							<thead>
								<tr>
									{largestRow.map((col, i) => {
										return (
											<td>
												<DropdownList wrap={false} label={null} placeholder="Select value" options={this.mappingOptions} selected={this.getDropdownSelectedItem(i)} changed={(v) => { this.setDropdownSelectedItem(i, v); }} />

												{this.selectionMap[i] != null && (this.selectionMap[i] == 'custom' || this.selectionMap[i].includes('ncf:'))
												&& <TextBox wrap={false} label="" cssClass="hidden" value={this.prefillNewCustomFieldName(i)} changed={(v) => { this.setDropdownSelectedItem(i, `ncf:${v}`); }} textType={TextBoxTextType.Text} />}
											</td>
										);
									})}
								</tr>
							</thead>
							<tbody>
								{this.getPreviewRows().map(row => (
									<tr>
										{largestRow.map((col, i) => (
											<td>
												{this.getDisplayValue(row[i])}
											</td>
										))}
									</tr>
								))}
							</tbody>
						</table>
					</div>
				)}

				<div class="import-mapper-settings">
					{this.$slots.default}
					<BootstrapToggle label={this.firstRowIsHeaderLabel ? this.firstRowIsHeaderLabel : 'First row is header'} value={this.firstRowHeader} changed={(e) => { this.firstRowHeader = e; }} />
				</div>
			</div>
		);
	}
}
