import { AfterViewInit, Directive, ElementRef, numberAttribute, inject, input } from '@angular/core'
import { Subject, fromEvent, takeUntil, tap, timer } from 'rxjs'

/**
 * Directive for loading images asynchronously
 */
@Directive({
	standalone: true,
	selector: '[kadiLoadingImage]',
})
export class LoadingImageDirective implements AfterViewInit {
	private readonly _elementRef = inject<ElementRef<HTMLImageElement>>(ElementRef)

	/** Interval to retry loading images that have failed to load */
	readonly retryInterval = input(2000, { transform: numberAttribute })

	private readonly imageLoadedSubject = new Subject<void>()

	ngAfterViewInit(): void {
		// Show a loading spinner when image is loading
		this._elementRef.nativeElement.style.background = 'url(assets/images/spinner.svg) center center / 50% no-repeat'

		// Create a temporary image element to load image in background
		const loadingImage = new Image()

		loadingImage.addEventListener('load', (event) => {
			this._elementRef.nativeElement.src = (event.target as HTMLImageElement).src
		})

		loadingImage.addEventListener('error', () => {
			timer(this.retryInterval())
				.pipe(
					takeUntil(this.imageLoadedSubject),
					tap(() => (loadingImage.src += `?${Date.now()}`)),
				)
				.subscribe()

			fromEvent(loadingImage, 'load')
				.pipe(tap(() => this.imageLoadedSubject.complete()))
				.subscribe()
		})

		loadingImage.src = this._elementRef.nativeElement.src
	}
}
