import {Injectable} from '@angular/core';
import {SCIdCard, SCThingOriginType, SCThingType, SCUserConfiguration} from '@openstapps/core';
import {from, of, Observable} from 'rxjs';
import {AuthHelperService} from '../auth/auth-helper.service';
import {mergeMap, concatWith, filter, map, startWith, catchError, tap} from 'rxjs/operators';
import {ConfigProvider} from '../config/config.provider';
import {HttpClient} from '@angular/common/http';
import {EncryptedStorageProvider} from '../storage/encrypted-storage.provider';

@Injectable({providedIn: 'root'})
export class IdCardsProvider {
  constructor(
    private authHelper: AuthHelperService,
    private config: ConfigProvider,
    private httpClient: HttpClient,
    private encryptedStorageProvider: EncryptedStorageProvider,
  ) {}

  getIdCards(): Observable<SCIdCard[]> {
    const feature = this.config.config.app.features.extern?.['idCards'];
    const auth = this.authHelper.getProvider(feature?.authProvider ?? 'default');
    const storedIdCards = from(
      this.encryptedStorageProvider.get<SCIdCard[]>('id-cards') as Promise<SCIdCard[]>,
    ).pipe(filter(it => it !== undefined));

    return auth.isLoggedIn$.pipe(
      mergeMap(isLoggedIn =>
        isLoggedIn
          ? feature
            ? storedIdCards.pipe(
                concatWith(
                  from(auth.getValidToken()).pipe(
                    mergeMap(token => this.fetchIdCards(feature.url, token.accessToken)),
                    catchError(() => storedIdCards),
                  ),
                ),
              )
            : auth.user$.pipe(
                filter(user => user !== undefined),
                map(userInfo => this.authHelper.getUserFromUserInfo(userInfo as object)),
                mergeMap(user => this.fetchFallbackIdCards(user)),
                startWith([]),
              )
          : of([]).pipe(tap({next: () => this.encryptedStorageProvider.delete('id-cards')})),
      ),
    );
  }

  private fetchIdCards(url: string, token: string): Observable<SCIdCard[]> {
    return this.httpClient
      .get<SCIdCard[]>(url, {
        headers: {
          Authorization: `Bearer ${token}`,
        },
        responseType: 'json',
      })
      .pipe(tap({next: idCards => this.encryptedStorageProvider.set('id-cards', idCards)}));
  }

  private fetchFallbackIdCards(user: SCUserConfiguration): Observable<SCIdCard[]> {
    return this.httpClient.get('/assets/examples/student-id.sample.svg', {responseType: 'text'}).pipe(
      map(svg => {
        let result = svg;
        for (const key in user) {
          result = result.replaceAll(`{{${key}}}`, (user as unknown as Record<string, string>)[key]);
        }
        return `data:image/svg+xml;utf8,${encodeURIComponent(result)}`;
      }),
      map(image => [
        {
          name: 'Student ID',
          image,
          type: SCThingType.IdCard,
          uid: '1234',
          origin: {
            name: 'Sample Origin',
            type: SCThingOriginType.Remote,
            indexed: new Date().toISOString(),
          },
        },
      ]),
    );
  }
}
