import {DomSanitizer, SafeHtml} from "@angular/platform-browser";
import {Injectable} from "@angular/core";
import {NgbModal, NgbModalOptions} from "@ng-bootstrap/ng-bootstrap";
import {ModalStatus} from "@app/_helpers/modal.states";
import {FormSubmitEvent} from "@app/_components/_abstract/abstract-data-form-component";

@Injectable({providedIn: 'root'})
export class AppHelperService {

    constructor(
        private sanitizer: DomSanitizer,
        private modalService: NgbModal,
    ) {
    }

    public extractId(iri: string | undefined | null): string {
        if (iri !== undefined && iri !== null) {
            const iriRegex = /\/(\d+)$/;
            const match = iri.match(iriRegex);
            if (match && match[1]) {
                return match[1];
            }
        }
        return "";
    }

    public convertDate(dateString: string | null, withTime = false) {
        // number 10 for input date (2024-03-15)
        // number 16 for input datetime-local (2024-04-28T03:22)
        if (dateString !== null) {
            const date = new Date(dateString);
            return date.toISOString().slice(0, withTime ? 16 : 10);
        }
        return "";
    }

    public getSafeLongtext(longtext: any): SafeHtml {
        if (longtext) {
            return this.sanitizer.bypassSecurityTrustHtml(longtext.replace(/\n/g, '<br>'));
        }
        return false;
    }

    public getModalOptions(): NgbModalOptions {
        return {centered: true} as NgbModalOptions;
    }

    public openModal(component: any, data: any, callback?: (callbackParam?: any) => void, callbackParam?: any): Promise<ModalStatus> {
        const modalRef = this.modalService.open(component);
        console.log(data);
        for (const key in data) {
            modalRef.componentInstance[key] = data[key];
        }

        return modalRef.componentInstance.submit.subscribe((event: FormSubmitEvent<any>) => {
            if (event.status === ModalStatus.Submitted) {
                modalRef.dismiss();
                if (callback) {
                    callback(callbackParam);
                }
            }
        });
    }

    public assertType<T>(value: any, type: string): asserts value is T {
        if (typeof value !== type) {
            throw new Error(`Expected ${type} but received ${typeof value}`);
        }
    }

    public getResourceLink(element: any, subResource?: any): string | null {
        let resourceLink: string = '/';
        element = subResource !== undefined ? element[subResource] : element;
        if (element === undefined) {
            return null;
        }
        return resourceLink + '/' + this.extractId(element['id']);
    }

    public getLink(element: any, url: any): string {
        return url + "/" + this.extractId(element['id']);
    }

    public dumpObject(obj: any): string {
        return JSON.stringify(obj, null, 2); // Das `null, 2` formatiert das JSON mit Einrückungen
    }

    public convertJsonldToJson<T extends object>(jsonldObj: any): T {

        // Erstelle ein neues Objekt ohne die JSON-LD spezifischen Eigenschaften
        const result: any = {};

        // Kopiere alle Eigenschaften außer context, id und type
        for (const key in jsonldObj) {
            if (
                jsonldObj.hasOwnProperty(key) &&
                key !== 'context' &&
                key !== 'id' &&
                key !== 'type'
            ) {
                // Wenn der Wert ein Objekt ist und JSON-LD Metadaten enthält, konvertiere es rekursiv
                if (
                    typeof jsonldObj[key] === 'object' &&
                    jsonldObj[key] !== null &&
                    (jsonldObj[key].context || jsonldObj[key].id || jsonldObj[key].type)
                ) {
                    result[key] = this.convertJsonldToJson(jsonldObj[key]);
                } else {
                    result[key] = jsonldObj[key];
                }
            }
        }

        return result as T;
    }

}