import { Injectable, inject } from '@angular/core'
import { NonNullableFormBuilder, Validators } from '@angular/forms'
import { CustomerAppSettings, DefaultService, FileUploadResponse } from '@api-client/angular'
import { startWithTap } from '@frontend/shared'
import { CreateHotToastRef, HotToastService } from '@ngxpert/hot-toast'
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'
import { EMPTY, Observable, catchError, map, of, switchMap, tap, zip } from 'rxjs'
import { I18nService } from '../../../core'
import { FileData, extractHttpErrorMessage } from '../../../shared'

@UntilDestroy({ checkProperties: true })
@Injectable()
export class PersonalizationSettingsStore {
	private readonly _toast = inject(HotToastService)
	private readonly _i18nService = inject(I18nService)
	private readonly _formBuilder = inject(NonNullableFormBuilder)
	private readonly _apiService = inject(DefaultService)

	form = this._formBuilder.group({
		displayName: this._formBuilder.control('', {
			validators: [Validators.required, Validators.minLength(2), Validators.maxLength(60)],
		}),
		logoUrl: this._formBuilder.control<string | undefined>(undefined),
		bannerUrl: this._formBuilder.control<string | undefined>(undefined),
		wifi: this._formBuilder.group({
			ssid: this._formBuilder.control<string | undefined>(undefined),
			password: this._formBuilder.control<string | undefined>(undefined),
		}),
		reviewUrl: this._formBuilder.control<string | undefined>(undefined),
	})

	bannerFile: File | undefined
	bannerFileData: FileData
	logoFile: File | undefined
	logoFileData: FileData

	constructor() {
		this.loadSettings()
	}

	get f() {
		return this.form.controls
	}

	onBannerChange(file: File, data: FileData): void {
		this.bannerFile = file
		this.bannerFileData = data
		this.form.markAsDirty()
	}

	onLogoChange(file: File, data: FileData): void {
		this.logoFile = file
		this.logoFileData = data
		this.form.markAsDirty()
	}

	save(): Observable<void> {
		return of('').pipe(
			// Upload images
			switchMap(() => {
				if (!this.bannerFile && !this.logoFile) return of('')
				const $apiCalls = []
				if (this.bannerFile) {
					$apiCalls.push(
						this.uploadFile(this.bannerFile, this._i18nService.translate('upload_banner_loading')).pipe(
							tap((_res) => this.f.bannerUrl.setValue(_res.url)),
						),
					)
				}
				if (this.logoFile) {
					$apiCalls.push(
						this.uploadFile(this.logoFile, this._i18nService.translate('upload_logo_loading')).pipe(
							tap((_res) => this.f.logoUrl.setValue(_res.url)),
						),
					)
				}
				return zip($apiCalls)
			}),
			map(() => {
				const settings = this.form.getRawValue() as CustomerAppSettings
				if (!settings.wifi?.ssid || !settings.wifi?.password) settings.wifi = undefined
				return settings
			}),
			switchMap((settings) =>
				this._apiService.settingsControllerSave({ customerApp: settings }).pipe(
					this._toast.observe({
						success: this._i18nService.translate('update_settings_success'),
						error: (error) => extractHttpErrorMessage(error),
					}),
					switchMap(() => this._apiService.settingsControllerFind()),
				),
			),
			tap((settings) => {
				this.bannerFile = this.bannerFileData = this.logoFile = this.logoFileData = undefined
				this.form.patchValue(settings.customerApp)
			}),
			map(() => void 0),
			catchError((error) => {
				this._toast.error(error.message)
				return EMPTY
			}),
		)
	}

	private loadSettings(): void {
		this._apiService
			.settingsControllerFind()
			.pipe(untilDestroyed(this))
			.subscribe(({ customerApp }) => {
				if (customerApp) {
					this.form.patchValue(customerApp)
				}
			})
	}

	private uploadFile(file: File, message: string): Observable<FileUploadResponse> {
		let toastRef: CreateHotToastRef<unknown>
		return this._apiService.storageControllerUploadFile(file).pipe(
			startWithTap(() => {
				toastRef = this._toast.loading(message)
			}),
			tap(() => toastRef.close()),
			catchError((error) => {
				this._toast.error(error.message)
				toastRef.close()
				return EMPTY
			}),
		)
	}
}
