// 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 { Component, Input, OnInit, ViewChild } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { CalendarOptions } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';
import timeGridPlugin from '@fullcalendar/timegrid';
import listPlugin from '@fullcalendar/list';
import { EventoAppuntamentoComponent } from './evento/evento-appuntamento.component';
import { FullCalendarComponent } from '@fullcalendar/angular';
import { ConfigService } from 'src/app/providers/config.service';
import { CompaniesService } from 'src/app/providers/companies.service';

@Component({
	selector: 'app-calendario-appuntamenti',
	templateUrl: './calendario-appuntamenti.component.html',
	styleUrls: ['./calendario-appuntamenti.component.scss'],
	standalone: false,
})
export class CalendarioAppuntamentiComponent implements OnInit {
	@ViewChild('calendar', { static: false }) calendarComponent!: FullCalendarComponent;

	@Input() cmp_id!: number;
	events: any[] = [];
	my_user: any = {};
	filter: any = {};
	tipo_utenza = '';
	curr_mese = 0;
	curr_anno = 0;
	settings_companies_appointment: any = {};
	settings_giorni_ferie_commessa: any = {};

	constructor(private modalController: ModalController, private companiesManager: CompaniesService, private config: ConfigService) {}

	ngOnInit() {
		this.my_user = this.config.getUser();
	}

	calendarOptions: CalendarOptions = {
		plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
		initialView: 'dayGridMonth',
		headerToolbar: {
			left: 'prev,next today',
			center: 'title',
			right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek',
		},
		titleFormat: {
			month: 'short',
			week: 'short',
			day: '2-digit',
		},
		/*titleFormat: { year: 'numeric', month: 'short',day: 'numeric' }   ,*/
		events: this.events,
		/*Clicco sul calendario e decido quando prendere appuntamento -> non più utilizzato*/
		// dateClick: this.handleDateClick.bind(this),
		eventClick: this.handleEventClick.bind(this),
		eventMouseEnter: this.handleEventMouseEnter.bind(this),
		datesSet: this.handleDatesSet.bind(this),
	};

	/*async handleDateClick(arg: any) {
    const modal = await this.modalController.create({
      component: EventoAppuntamentoComponent,
      //componentProps: { date: arg.dateStr }
    });

    modal.onDidDismiss().then((result: any) => {
        this.getListaAppuntamenti();
    });

    return await modal.present();
  }*/

	handleEventMouseEnter(info: any) {
		const start = new Date(info.event.start);
		const end = new Date(info.event.end);

		const durationInMinutes = (end.getTime() - start.getTime()) / (1000 * 60);

		info.el.setAttribute('title', `${info.event.title} - Durata: ${durationInMinutes} minuti`);
	}

	async handleEventClick(info: any) {
		const appuntamento = JSON.parse(JSON.stringify(info.event));
		const modal = await this.modalController.create({
			component: EventoAppuntamentoComponent,
			componentProps: { date: appuntamento, tipo_utenza: this.tipo_utenza, cmp_id: this.cmp_id },
		});

		modal.present();

		const { role } = await modal.onDidDismiss();
		if (role === 'cancel') {
			this.close();
		}
	}

	handleDatesSet(event: any) {
		const viewStart = event.view.currentStart;

		this.curr_mese = viewStart.getMonth() + 1;
		this.curr_anno = viewStart.getFullYear();

		if (this.tipo_utenza != 'ADMIN') {
			this.getSettingsCompaniesAppointment();
		} else {
			this.getAppointmentsList();
		}
	}

	getSettingsCompaniesAppointment() {
		if (this.cmp_id > 0) {
			this.companiesManager.getSettingsCompaniesAppointment(this.cmp_id).subscribe((data: any) => {
				if (data) {
					this.settings_companies_appointment = JSON.parse(data.calendario);
					this.settings_giorni_ferie_commessa = JSON.parse(data.calendario_no_work);
					if (this.settings_companies_appointment) {
						this.getAppointmentsList();
					} else {
						this.config.presentToastWarning("Nessun orario di appuntamento dell'azienda disponibile");
					}
				}
			});
		}
	}

	getAppointmentsList() {
		let filter: any = {};
		filter.pagina = 1;
		filter.righePagina = 10000;
		filter.orderBy = 'apt_app_id DESC';
		filter.cmp_id = this.cmp_id;

		this.events = [];
		let slot_disponibili: any[] = [];

		if (this.tipo_utenza != 'ADMIN') {
			let array_days = this.getDaysInMonthWithWeekdays(this.curr_anno, this.curr_mese, this.settings_companies_appointment.giorni_settimana, this.settings_giorni_ferie_commessa);

			slot_disponibili = this.creaSlotAppuntamento(
				array_days,
				this.curr_anno,
				this.curr_mese,
				this.settings_companies_appointment.mattina_inizio,
				this.settings_companies_appointment.mattina_fine,
				this.settings_companies_appointment.pomeriggio_inizio,
				this.settings_companies_appointment.pomeriggio_fine,
			);
		}

		this.companiesManager.getAppointmentsList(filter).subscribe((res: any) => {
			if (res) {
				for (let i = 0; i < res.length; i++) {
					switch (res[i].stato.id) {
						case 1:
							res[i].backgroundColor = 'blue';
							break;
						case 2:
							res[i].backgroundColor = 'green';
							break;
						case 3:
							res[i].backgroundColor = 'red';
							break;
					}

					if (this.tipo_utenza != 'ADMIN') {
						if (this.my_user.usr_id != res[i].usr_id) {
							res[i].title = 'Slot Occupato';
							res[i].backgroundColor = 'red';
						}
					}
				}

				if (this.tipo_utenza != 'ADMIN') {
					this.events = this.sostituisciSlotFittizi(slot_disponibili, res);
				} else {
					this.events = res;
				}

				this.calendarOptions.events = [...this.events];
			}
		});
	}

	getDaysInMonthWithWeekdays(year: number, month: number, giorniAppuntamento: string[], giorniFerie: { da: string; a: string }[]) {
		// Ottieni il numero di giorni nel mese specificato
		const daysInMonth = new Date(year, month, 0).getDate();

		// Data di oggi e di domani
		const today = new Date();
		const tomorrow = new Date(today);
		tomorrow.setDate(today.getDate() + 1);

		const ferieSet = new Set<string>();
		for (const intervallo of giorniFerie) {
			const start = new Date(intervallo.da);
			const end = new Date(intervallo.a);
			let current = new Date(start);

			while (current <= end) {
				ferieSet.add(current.toDateString());
				current.setDate(current.getDate() + 1);
			}
		}

		// Genera un array di oggetti contenenti giorno, nome del giorno e la data completa
		return Array.from({ length: daysInMonth }, (_, i) => {
			const date = new Date(year, month - 1, i + 1); // Usa month-1 perché i mesi in JavaScript partono da 0
			const weekdayIndex = date.getDay(); // Ottieni l'indice del giorno della settimana (0 per Domenica, 1 per Lunedì, ecc.)

			return { day: i + 1, fullDate: date, weekdayIndex };
		}).filter((dayObj) => {
			// Filtra solo i giorni successivi a domani e compatibili con `giorniAppuntamento` e `giorniFerie`
			const isAfterTomorrow = dayObj.fullDate >= tomorrow;
			const isAllowedWeekday = giorniAppuntamento.includes(dayObj.weekdayIndex.toString());
			const isNotHoliday = !ferieSet.has(dayObj.fullDate.toDateString());

			return isAfterTomorrow && isAllowedWeekday && isNotHoliday;
		});
	}

	creaSlotAppuntamento(daysArray: any, year: number, month: number, mattina_inizio: number, mattina_fine: number, pomeriggio_inizio: number, pomeriggio_fine: number) {
		const result: any[] = [];

		// Ottieni ora e minuti per mattina e pomeriggio
		let mattina_inizio_ore = new Date(mattina_inizio).getHours();
		let mattina_inizio_minuti = new Date(mattina_inizio).getMinutes();

		let mattina_fine_ore = new Date(mattina_fine).getHours();
		let mattina_fine_minuti = new Date(mattina_fine).getMinutes();

		let pomeriggio_inizio_ore = new Date(pomeriggio_inizio).getHours();
		let pomeriggio_inizio_minuti = new Date(pomeriggio_inizio).getMinutes();

		let pomeriggio_fine_ore = new Date(pomeriggio_fine).getHours();
		let pomeriggio_fine_minuti = new Date(pomeriggio_fine).getMinutes();

		daysArray.forEach((dayObj: any) => {
			const { day } = dayObj;

			// Slot mattutini
			for (let hour = mattina_inizio_ore; hour <= mattina_fine_ore; hour++) {
				for (let minute = hour === mattina_inizio_ore ? mattina_inizio_minuti : 0; minute < 60; minute += 30) {
					// Verifica se siamo nell'ultimo slot mattutino e crea l'ultimo slot completo
					if (hour === mattina_fine_ore && minute === mattina_fine_minuti) {
						result.push(this.creaSlot(year, month, day, hour, minute, hour, minute + 30));
						break;
					}
					if (hour === mattina_fine_ore && minute > mattina_fine_minuti) break;
					result.push(this.creaSlot(year, month, day, hour, minute, hour, minute + 30));
				}
			}

			// Slot pomeridiani
			for (let hour = pomeriggio_inizio_ore; hour <= pomeriggio_fine_ore; hour++) {
				for (let minute = hour === pomeriggio_inizio_ore ? pomeriggio_inizio_minuti : 0; minute < 60; minute += 30) {
					// Verifica se siamo nell'ultimo slot pomeridiano e crea l'ultimo slot completo
					if (hour === pomeriggio_fine_ore && minute === pomeriggio_fine_minuti) {
						result.push(this.creaSlot(year, month, day, hour, minute, hour, minute + 30));
						break;
					}
					if (hour === pomeriggio_fine_ore && minute > pomeriggio_fine_minuti) break;
					result.push(this.creaSlot(year, month, day, hour, minute, hour, minute + 30));
				}
			}
		});

		return result;
	}

	creaSlot(year: number, month: number, day: number, startHour: number, startMinute: number, endHour: number, endMinute: number) {
		const start = new Date(year, month - 1, day, startHour, startMinute, 0);
		const end = new Date(year, month - 1, day, endHour, endMinute, 0);

		let slot = {
			title: 'Slot Disponibile',
			start: start.toISOString(),
			end: end.toISOString(),
			backgroundColor: 'green',
			app_id: -1,
		};

		return slot;
	}

	sostituisciSlotFittizi(conto: any, appuntamenti: any) {
		const mappaAppuntamenti = new Map<string, any>();

		// Filtra gli appuntamenti escludendo quelli con stato.id === 3 (CANCELLATO)
		appuntamenti
			.filter((appuntamento: any) => appuntamento.stato?.id !== 3)
			.forEach((appuntamento: any) => {
				const key = `${appuntamento.start}-${appuntamento.end}`;
				mappaAppuntamenti.set(key, appuntamento);
			});

		// Aggiorna gli slot fittizi con quelli reali
		const risultato = conto.map((slotFittizio: any) => {
			const key = `${new Date(slotFittizio.start).getTime()}-${new Date(slotFittizio.end).getTime()}`;

			if (mappaAppuntamenti.has(key)) {
				const appuntamentoReale = mappaAppuntamenti.get(key);
				return appuntamentoReale;
			} else {
				return slotFittizio;
			}
		});

		return risultato;
	}

	close() {
		return this.modalController.dismiss(null, 'reload');
	}
}
