// Questo file fa parte di MyTown.
// MyTown è software libero: puoi ridistribuirlo e/o modificarlo secondo
// i termini della GNU Affero General Public License come pubblicata dalla
// Free Software Foundation, versione 3.
// Distribuito senza ALCUNA GARANZIA; vedi la GNU AGPL v3 per i dettagli.
// Copyright (C) Kondor Consulting & Services S.r.l.
// SPDX-License-Identifier: AGPL-3.0-or-later

import { DatePipe } from '@angular/common';
import { Component, ElementRef, EventEmitter, Input, Output, SimpleChange, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { IonInput, IonPopover } from '@ionic/angular';
import { ConfigService } from 'src/app/providers/config.service';

@Component({
	selector: 'app-calendar-component',
	templateUrl: './calendar.component.html',
	styleUrls: ['./calendar.component.scss'],
	standalone: false,
})
export class CalendarComponent {
	@Input() data_in!: any;
	@Input() type: string = 'date';
	@Output() data_out = new EventEmitter<Date | null>();
	@Input() disabled: boolean = false;
	@Input() tabindex: number = -1;
	@Input() suggestions: string[] = [];

	filteredSuggestions: string[] = [];
	showSuggestions: boolean = false;
	focusedSuggestionIndex: number = -1;

	@ViewChild('ord_date_popover', { static: false }) ord_date_popover!: IonPopover;
	@ViewChild('timeInput', { static: true }) timeInput?: ElementRef;
	@ViewChild('in_digit') digit!: IonInput;

	list_hh_mm: any[] = [];
	ore = '';

	ionicForm: FormGroup = this.formBuilder.group({
		data: [''],
	});

	lst_uniqueId = '';

	constructor(private formBuilder: FormBuilder, public datePipe: DatePipe, public config: ConfigService) {}

	ngOnInit() {
		this.list_hh_mm = [];
		for (let i = 6; i < 22; i++) {
			let hh = '';
			if (i < 10) {
				hh = '0' + i;
			} else {
				hh = '' + i;
			}
			this.list_hh_mm.push(hh + ':00');
			this.list_hh_mm.push(hh + ':30');
		}
		this.lst_uniqueId = Math.random().toString(36).substring(7);

		if (this.disabled) {
			this.ionicForm.get('data')?.disable();
		}
	}

	ngOnChanges(changes: { [propName: string]: SimpleChange }) {
		if (changes['suggestions']) {
			return;
		}

		if (this.data_in && this.data_in != '' && this.data_in != undefined) {
			let data_input = this.data_in.trim();
			this.data_in = data_input;
			if (this.type == 'date') {
				const parsedDate = this.parseDateString(data_input);
				if (parsedDate) {
					this.ionicForm.controls['data'].setValue(this.datePipe.transform(parsedDate, 'dd/MM/yyyy'));
				}
			} else if (this.type == 'time') {
				let tmp_ore = this.datePipe.transform(new Date(data_input), 'HH:mm');
				if (tmp_ore) {
					this.ore = tmp_ore;
				}
			}
		}
	}

	parseDateString(dateString: string): Date | null {
		if (dateString && typeof dateString == 'string') {
			const [day, month, year] = dateString.split('/').map(Number);
			if (day && month && year) {
				return new Date(year, month - 1, day); // JavaScript months are 0-based
			}
		}

		return null;
	}

	setOre(e: any) {
		this.data_out.emit(this.timeStringToDate(e.currentTarget.value));
	}

	timeStringToDate(timeString: string, referenceDate: Date = new Date()): Date {
		// Dividiamo la stringa del tempo per ottenere ore e minuti
		const [hours, minutes] = timeString.split(':').map(Number);

		// Creiamo una nuova data basata sulla data di riferimento e impostiamo ore e minuti
		const date = new Date(referenceDate);
		date.setHours(hours);
		date.setMinutes(minutes);
		date.setSeconds(0);
		date.setMilliseconds(0);

		return date;
	}

	setDataControll(e: any) {
		let val = e.currentTarget.value;
		let valid = false;
		const regex = /^\d{2}\/\d{2}\/\d{4}$/;
		if (val && val.trim()) {
			valid = regex.test(e.currentTarget.value);
			if (valid) {
				const parsedDate = this.parseDateString(e.currentTarget.value);
				if (parsedDate) {
					this.data_in = this.datePipe.transform(parsedDate, 'dd/MM/yyyy');
					this.data_out.emit(parsedDate);
				} else {
					this.data_out.emit(null);
				}
			} else {
				if (!this.showSuggestions) {
					this.data_in = '';
					this.config.presentToastError('Data non corretta, usare il formato dd/mm/yyyy.');
					this.data_out.emit(null);
				}
			}
		} else {
			this.data_out.emit(null);
		}

		if (this.suggestions.length > 0) {
			setTimeout(() => {
				if (this.showSuggestions) {
					this.clearFilterSuggestions();
					if (val && val.trim() && !valid) {
						valid = regex.test(this.data_in);
						if (!valid) {
							this.data_in = '';
							this.config.presentToastError('Data non corretta, usare il formato dd/mm/yyyy.');
							this.data_out.emit(null);
						}
					}
				}
			}, 500);
		}
	}

	async setData(e: any) {
		const parsedDate = new Date(e.currentTarget.value);
		if (!isNaN(parsedDate.getTime())) {
			this.data_in = this.datePipe.transform(parsedDate, 'dd/MM/yyyy');
			this.data_out.emit(parsedDate);
		}
		await this.ord_date_popover.dismiss();
		this.clearFilterSuggestions();
	}

	public reset() {
		this.data_in = '';
	}

	onInput(event: any): void {
		if (this.suggestions.length > 0) {
			const inputValue = event.target.value;
			if (inputValue) {
				this.filterSuggestions(inputValue);
			} else {
				this.clearFilterSuggestions();
			}
		}
	}

	filterSuggestions(inputValue: string) {
		this.filteredSuggestions = this.suggestions.filter((suggestion) => suggestion.toLowerCase().startsWith(inputValue.toLowerCase())).slice(0, 20);
		this.showSuggestions = this.filteredSuggestions.length > 0;
		this.focusedSuggestionIndex = -1;
	}

	clearFilterSuggestions() {
		this.filteredSuggestions = [];
		this.showSuggestions = false;
		this.focusedSuggestionIndex = -1;
	}

	selectSuggestion(suggestion: string): void {
		this.showSuggestions = false;
		this.clearFilterSuggestions();
		this.data_in = suggestion;
		const parsedDate = this.parseDateString(suggestion);
		if (parsedDate) {
			this.data_out.emit(parsedDate);
		} else {
			this.data_out.emit(null);
		}
	}

	onSuggestionKeyDown(event: KeyboardEvent, suggestion: string): void {
		if (event.key === 'Enter' || event.key === ' ') {
			event.preventDefault();
			this.selectSuggestion(suggestion);
		}
	}

	onKeyDown(event: KeyboardEvent): void {
		if (this.showSuggestions) {
			if (event.key === 'ArrowDown') {
				event.preventDefault();
				this.focusedSuggestionIndex = (this.focusedSuggestionIndex + 1) % this.filteredSuggestions.length;
				this.focusSuggestionItem();
			} else if (event.key === 'ArrowUp') {
				event.preventDefault();
				this.focusedSuggestionIndex = (this.focusedSuggestionIndex - 1 + this.filteredSuggestions.length) % this.filteredSuggestions.length;
				this.focusSuggestionItem();
			} else if (event.key === 'Enter' || event.key === ' ') {
				if (this.focusedSuggestionIndex >= 0 && this.focusedSuggestionIndex < this.filteredSuggestions.length) {
					event.preventDefault();
					this.selectSuggestion(this.filteredSuggestions[this.focusedSuggestionIndex]);
				}
			}
		}
	}

	private focusSuggestionItem(): void {
		const suggestionItems = document.querySelectorAll('[suggestion-item]');
		if (this.focusedSuggestionIndex >= 0 && this.focusedSuggestionIndex < suggestionItems.length) {
			suggestionItems.forEach((item, index) => {
				if (index === this.focusedSuggestionIndex) {
					item.classList.add('focused');
				} else {
					item.classList.remove('focused');
				}
			});

			const focusedItem = suggestionItems[this.focusedSuggestionIndex] as HTMLElement;
			focusedItem.scrollIntoView({
				block: 'nearest', // 'nearest' per farlo scorrere solo se necessario
				inline: 'nearest',
				behavior: 'smooth', // Scorrimento fluido
			});
			focusedItem.focus();
		}
	}

	setFocus() {
		this.digit.setFocus().then(() => {
			const nativeInput = (this.digit as any).el.querySelector('input');
			if (nativeInput) {
				nativeInput.select();
			}
		});
	}
}
