// 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 { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { ConfigService } from './config.service';
import { Appointment, AppointmentFilter, StatusTransitionRequest } from 'src/models/biz-appointments/appointment.model';
import { AppointmentAttachment } from 'src/models/biz-appointments/appointment-attachment.model';
import { FreeSlot } from 'src/models/biz-appointments/availability.model';

@Injectable({
	providedIn: 'root',
})
export class BizAppointmentsService {
	constructor(
		private http: HttpClient,
		private configService: ConfigService,
	) {}

	private get baseUrl(): string {
		return this.configService.serviceUrl_BizAppointments;
	}

	private formatDateParam(value: string | Date | undefined): string | null {
		if (!value) return null;
		if (value instanceof Date) {
			const y = value.getFullYear();
			const m = String(value.getMonth() + 1).padStart(2, '0');
			const d = String(value.getDate()).padStart(2, '0');
			return `${y}-${m}-${d}`;
		}
		return value;
	}

	getAppointments(cmp_id: number, txtsearch: string = '', order_by: string = '', limit: number = 20, offset: number = 0, filters?: AppointmentFilter): Observable<{ list: Appointment[]; totPagine: number; totalRows: number }> {
		let url = `${this.baseUrl}appointments/list?cmp_id=${cmp_id}&txtsearch=${encodeURIComponent(txtsearch)}&order_by=${encodeURIComponent(order_by)}&limit=${limit}&offset=${offset}`;

		if (filters) {
			if (filters.status) url += `&status=${filters.status}`;
			if (filters.service_type_id) url += `&service_type_id=${filters.service_type_id}`;
			if (filters.operator_em_id) url += `&operator_em_id=${filters.operator_em_id}`;
			if (filters.client_usr_id) url += `&client_usr_id=${filters.client_usr_id}`;
			if (filters.date_from) url += `&date_from=${this.formatDateParam(filters.date_from)}`;
			if (filters.date_to) url += `&date_to=${this.formatDateParam(filters.date_to)}`;
		}

		return this.http.get(url, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	getAppointment(id: number): Observable<Appointment> {
		return this.http.get(`${this.baseUrl}appointments/get/${id}`, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	insertAppointment(appointment: Partial<Appointment>): Observable<number> {
		return this.http.post(`${this.baseUrl}appointments/add`, appointment, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	updateAppointment(appointment: Partial<Appointment>): Observable<number> {
		return this.http.put(`${this.baseUrl}appointments/upd`, appointment, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	deleteAppointment(id: number): Observable<number> {
		return this.http.delete(`${this.baseUrl}appointments/del/${id}`, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	transitionStatus(apt_id: number, request: StatusTransitionRequest): Observable<Appointment> {
		return this.http.post(`${this.baseUrl}appointments/transition/${apt_id}`, request, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	/** Imposta/azzera la scadenza dell'evento programmatico (due_date null = disattiva) + ricorrenza. */
	setProgrammaticDeadline(apt_id: number, due_date: string | null, recurrence_months?: number | null, reminder_lead_days?: number | null): Observable<any> {
		const body: any = { due_date };
		if (recurrence_months != null) body.recurrence_months = recurrence_months;
		if (reminder_lead_days != null) body.reminder_lead_days = reminder_lead_days;
		return this.http.post(`${this.baseUrl}appointments/programmatic/${apt_id}`, body, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	getAppointmentsForCalendar(cmp_id: number, date_from: string, date_to: string, filters?: AppointmentFilter): Observable<Appointment[]> {
		let url = `${this.baseUrl}appointments/calendar?cmp_id=${cmp_id}&date_from=${date_from}&date_to=${date_to}`;

		if (filters) {
			if (filters.status) url += `&status=${filters.status}`;
			if (filters.service_type_id) url += `&service_type_id=${filters.service_type_id}`;
			if (filters.operator_em_id) url += `&operator_em_id=${filters.operator_em_id}`;
		}

		return this.http.get(url, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	getFreeSlots(cmp_id: number, service_type_id: number, date_from: string, date_to: string, operator_em_id?: number, duration_minutes?: number): Observable<FreeSlot[]> {
		let url = `${this.baseUrl}appointments/free-slots?cmp_id=${cmp_id}&service_type_id=${service_type_id}&date_from=${date_from}&date_to=${date_to}`;
		if (operator_em_id) url += `&operator_em_id=${operator_em_id}`;
		if (duration_minutes && duration_minutes > 0) url += `&duration_minutes=${duration_minutes}`;

		return this.http.get(url, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	// --- Allegati ---

	uploadAttachment(apt_id: number, file: File, description: string = ''): Observable<AppointmentAttachment> {
		const formData = new FormData();
		formData.append('file', file);
		formData.append('description', description);

		return this.http.post(`${this.baseUrl}appointment-attachments/upload/${apt_id}`, formData, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	getAttachments(apt_id: number): Observable<AppointmentAttachment[]> {
		return this.http.get(`${this.baseUrl}appointment-attachments/list/${apt_id}`, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	downloadAttachment(att_id: number): Observable<any> {
		return this.http.get(`${this.baseUrl}appointment-attachments/download/${att_id}`, { observe: 'response' }).pipe(map((response: any) => response.body));
	}

	deleteAttachment(att_id: number): Observable<number> {
		return this.http.delete(`${this.baseUrl}appointment-attachments/del/${att_id}`, { observe: 'response' }).pipe(map((response: any) => response.body));
	}
}
