import { DestroyRef, inject, Injectable } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { TenantsService } from '@common-ui/tenants';
import { log } from '@common-ui/utils';
import { getConfig } from '@iqser/common-ui';
import { IMessage, IWatchParams, RxStomp } from '@stomp/rx-stomp';
import { StompHeaders } from '@stomp/stompjs';

import { NGXLogger } from 'ngx-logger';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';

@Injectable({
    providedIn: 'root',
})
export class WebSocketService extends RxStomp {
    readonly #logger = inject(NGXLogger);
    readonly #config = getConfig();
    readonly #tenantService = inject(TenantsService);
    readonly #destroyRef = inject(DestroyRef);

    url: string;

    constructor() {
        super();
    }

    get topicPrefix() {
        return '/topic/' + this.#tenantService.activeTenantId + '/';
    }

    watch(opts: IWatchParams): Observable<IMessage>;
    watch(destination: string, headers?: StompHeaders): Observable<IMessage>;
    watch(opts: string | IWatchParams, headers?: StompHeaders): Observable<IMessage> {
        if (typeof opts === 'string') {
            return super.watch(this.topicPrefix + opts, headers);
        }

        return super.watch(opts);
    }

    listen<T>(topic: string): Observable<T> {
        return this.watch(topic).pipe(
            log('LISTEN LOG'),
            tap(msg => console.log(msg.body)),
            map(msg => JSON.parse(msg.body)),
        );
    }

    connect(url: string) {
        this.url = url;
        this.configureConnection();

        this.connectionState$.pipe(log('[WS] Connection state')).subscribe();
        this.webSocketErrors$.pipe(log('[WS] Errors')).subscribe(frame => this.configureConnection());
        this.stompErrors$
            .pipe(
                tap(frame => {
                    console.error(frame);
                    console.error('Broker reported error: ' + frame.headers['message']);
                    console.error('Additional details: ' + frame.body);
                }),
                takeUntilDestroyed(this.#destroyRef),
            )
            .subscribe();

        this.activate();
    }

    private configureConnection() {
        const headers = { Authorization: 'Bearer ' + localStorage.getItem('token') };
        console.log(headers);
        this.configure({
            debug: (msg: string) => this.#logger.debug(msg),
            brokerURL: this.#config.API_URL + this.url,
            connectHeaders: headers,
        });
    }
}
