import {Component} from '@angular/core';
import {AbstractDataFormComponent} from "@app/_components/_abstract/abstract-data-form-component";
import {
    LocationService, TripJsonld,
    TripLocationJsonld,
    TripLocationService,
} from "@app/core/api/v1";
import {AppHelperService} from "@app/_helpers/app-helper.service";
import {TranslateService} from "@ngx-translate/core";
import {Router} from "@angular/router";
import {ROUTE_BASE_DATA} from "@app/app-routing.module";
import {tripLocationForm} from "@app/_forms/apiForms";
import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type";
import {ListColDefinition} from "@app/_components/list/list-col-definition";
import {SearchSelectComponent} from "@app/_components/search-select/search-select.component";

@Component({
  selector: 'app-trip-location-form',
  templateUrl: './trip-location-form.component.html',
  styleUrl: './trip-location-form.component.scss'
})
export class TripLocationFormComponent extends AbstractDataFormComponent<TripLocationJsonld> {

    protected readonly tripLocationForm = tripLocationForm;
    protected readonly SearchSelectComponent = SearchSelectComponent;
    protected locationColDefinitions: ListColDefinition[];
    protected trip!: TripJsonld;
    protected newArrivalDateTime?: string;
    protected newDepartureDateTime?: string;
    protected tripLocationEntries: TripLocationJsonld[];

    constructor(
        private tripLocationService: TripLocationService,
        private locationService: LocationService,
        appHelperService: AppHelperService,
        translateService: TranslateService,
        router: Router
    ) {
        super(
            tripLocationForm,
            appHelperService,
            (data: TripLocationJsonld) => {
                return this.tripLocationService.tripLocationsPost(data);
            },
            (id: string | number, data: TripLocationJsonld) =>
                this.tripLocationService.tripLocationsIdPatch(
                    id.toString(),
                    this.appHelperService.convertJsonldToJson(data)
                ),
            (id: string | number) => this.tripLocationService.tripLocationsIdDelete(id.toString()),
            translateService,
            router
        );
        this.tripLocationEntries = [];
        this.redirectAfterDelete = '/' + ROUTE_BASE_DATA;
        this.locationColDefinitions = SearchSelectComponent.getDefaultColDefLocations();
    }

    override ngOnInit() {
        super.ngOnInit();
        this.form.get('tripIri')?.setValue(this.trip.id);
        console.log(this.newArrivalDateTime);
        console.log(this.newDepartureDateTime);
        if (!this.isEditMode()) {
            this.form.get('arrivalDateTime')?.setValue(this.newArrivalDateTime);
            this.form.get('departureDateTime')?.setValue(this.newDepartureDateTime);
        } else {
            this.form.get('arrivalDateTime')?.setValue(this.data?.arrivalDateTime);
            this.form.get('departureDateTime')?.setValue(this.data?.departureDateTime);
        }
    }

    getLocations: ListGetDataFunctionType = (index: number, pageSize: number, term?: string) => {
        return this.locationService.locationsGetCollection(
            index,
            pageSize,
            term
        );
    }

    override onSubmit() {
        const formData = this.form.value as TripLocationJsonld;

        if (this.hasDateOverlap(formData)) {
            this.translateService?.get('trip_location.overlap_error').subscribe((error: string) => {
                alert(error);
            });
            return;
        }

        super.onSubmit();
    }

    private hasDateOverlap(formData: TripLocationJsonld): boolean {
        // Wenn kein Datum gesetzt ist, kann keine Überlappung stattfinden
        if (!formData.arrivalDateTime && !formData.departureDateTime) {
            return false;
        }

        // Wenn wir im Edit-Modus sind, entferne den aktuellen Eintrag aus der Überprüfung
        const entriesToCheck = this.isEditMode()
            ? this.tripLocationEntries.filter(entry => entry.id !== this.data?.id)
            : this.tripLocationEntries;

        for (const entry of entriesToCheck) {
            // Fall 1: Nur ein Datum ist gesetzt in formData
            if (formData.arrivalDateTime && !formData.departureDateTime) {
                // Arrival date darf nicht mit anderen arrival dates übereinstimmen
                if (entry.arrivalDateTime === formData.arrivalDateTime) {
                    return true;
                }

                // Überprüfe, ob arrival innerhalb eines existierenden Zeitraums liegt
                // ABER: arrival darf gleich mit einem departure sein
                if (entry.arrivalDateTime && entry.departureDateTime) {
                    const arrivalDate = new Date(formData.arrivalDateTime);
                    const entryArrival = new Date(entry.arrivalDateTime);
                    const entryDeparture = new Date(entry.departureDateTime);

                    // Liegt innerhalb des Zeitraums, aber ist NICHT gleich dem departure
                    if (arrivalDate > entryArrival && arrivalDate < entryDeparture) {
                        return true;
                    }
                }
            }
            else if (!formData.arrivalDateTime && formData.departureDateTime) {
                // Departure date darf nicht mit anderen departure dates übereinstimmen
                if (entry.departureDateTime === formData.departureDateTime) {
                    return true;
                }

                // Überprüfe, ob departure innerhalb eines existierenden Zeitraums liegt
                // ABER: departure darf gleich mit einem arrival sein
                if (entry.arrivalDateTime && entry.departureDateTime) {
                    const departureDate = new Date(formData.departureDateTime);
                    const entryArrival = new Date(entry.arrivalDateTime);
                    const entryDeparture = new Date(entry.departureDateTime);

                    // Liegt innerhalb des Zeitraums, aber ist NICHT gleich dem arrival
                    if (departureDate > entryArrival && departureDate < entryDeparture) {
                        return true;
                    }
                }
            }
            // Fall 2: Beide Daten sind gesetzt in formData, überprüfe auf Überlappung
            else if (formData.arrivalDateTime && formData.departureDateTime) {
                const formArrival = new Date(formData.arrivalDateTime);
                const formDeparture = new Date(formData.departureDateTime);

                // Wenn der andere Eintrag beide Daten hat
                if (entry.arrivalDateTime && entry.departureDateTime) {
                    const entryArrival = new Date(entry.arrivalDateTime);
                    const entryDeparture = new Date(entry.departureDateTime);

                    // Überprüfung auf Überlappung der Zeiträume, erlaubt grenzen zu teilen
                    // Formular-Zeitraum darf vor oder nach dem Entry-Zeitraum liegen,
                    // oder die Grenzen dürfen gleich sein (departure gleich arrival oder umgekehrt)
                    if (
                        // Überlappung, aber nicht nur am Rand
                        (formArrival < entryDeparture && formDeparture > entryArrival) &&
                        // Erlaubt: formDeparture === entryArrival ODER formArrival === entryDeparture
                        !(formDeparture.getTime() === entryArrival.getTime() ||
                            formArrival.getTime() === entryDeparture.getTime())
                    ) {
                        return true;
                    }
                }
                // Wenn der andere Eintrag nur arrival hat
                else if (entry.arrivalDateTime && !entry.departureDateTime) {
                    const entryArrival = new Date(entry.arrivalDateTime);

                    // Das arrival des anderen Eintrags darf nicht innerhalb des neuen Zeitraums liegen
                    // ABER: Es darf am Rand liegen (gleich mit formDeparture)
                    if (entryArrival > formArrival && entryArrival < formDeparture) {
                        return true;
                    }
                }
                // Wenn der andere Eintrag nur departure hat
                else if (!entry.arrivalDateTime && entry.departureDateTime) {
                    const entryDeparture = new Date(entry.departureDateTime);

                    // Das departure des anderen Eintrags darf nicht innerhalb des neuen Zeitraums liegen
                    // ABER: Es darf am Rand liegen (gleich mit formArrival)
                    if (entryDeparture > formArrival && entryDeparture < formDeparture) {
                        return true;
                    }
                }
            }
        }

        return false;
    }
}
