import { CommonModule } from '@angular/common';
import {
    Component,
    computed,
    inject,
    Input,
    OnDestroy,
    OnInit,
    signal,
    ViewEncapsulation,
} from '@angular/core';
import {
    FormArray,
    FormBuilder,
    FormControl,
    ReactiveFormsModule,
    Validators,
} from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import {
    MAT_DIALOG_DATA,
    MatDialog,
    MatDialogModule,
} from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { EpgRuntimeBridgeService, EpgService } from '@iptvnator/epg/data-access';
import { SettingsContextService } from '@iptvnator/workspace/shell/util';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DialogService } from '@iptvnator/ui/components';
import {
    PlaylistActions,
    selectAllPlaylistsMeta,
    selectIsEpgAvailable,
} from '@iptvnator/m3u-state';
import { firstValueFrom, take } from 'rxjs';
import {
    DatabaseService,
    DataService,
    DbOperationEvent,
    PlaylistBackupImportSummary,
    PlaylistBackupService,
    PlaylistsService,
    RuntimeCapabilitiesService,
} from '@iptvnator/services';
import {
    EmbeddedMpvSupport,
    CoverSize,
    Language,
    normalizeExternalPlayerArguments,
    Settings,
    StartupBehavior,
    StreamFormat,
    Theme,
    VideoPlayer,
} from '@iptvnator/shared/interfaces';
import { SettingsStore } from '../services/settings-store.service';
import { SettingsService } from './../services/settings.service';
import { SettingsAboutSectionComponent } from './settings-about-section.component';
import { SettingsBackupSectionComponent } from './settings-backup-section.component';
import {
    SettingsDeleteAllPlaylistsDialogComponent,
    SettingsDeleteAllPlaylistsDialogData,
} from './settings-delete-all-playlists-dialog.component';
import { SettingsEpgSectionComponent } from './settings-epg-section.component';
import { createEpgUrlControl } from './settings-form.utils';
import { SettingsGeneralSectionComponent } from './settings-general-section.component';
import {
    SettingsPlaylistDeleteSummary,
    SettingsSection,
} from './settings.models';
import {
    buildSettingsSectionNavItems,
    SETTINGS_COVER_SIZE_OPTIONS,
    SETTINGS_EMBEDDED_PLAYER_OPTIONS,
    SETTINGS_OS_PLAYER_OPTIONS,
    SETTINGS_STARTUP_BEHAVIOR_OPTIONS,
    SETTINGS_THEME_OPTIONS,
} from './settings-options';
import { SettingsPlaybackSectionComponent } from './settings-playback-section.component';
import { SettingsRemoteControlSectionComponent } from './settings-remote-control-section.component';
import { SettingsResetSectionComponent } from './settings-reset-section.component';
import { SettingsSectionScrollDirective } from './settings-section-scroll.directive';

@Component({
    templateUrl: './settings.component.html',
    styleUrls: ['./settings.component.scss'],
    host: {
        class: 'settings-page-host',
    },
    encapsulation: ViewEncapsulation.None,
    imports: [
        CommonModule,
        MatButtonModule,
        MatIconModule,
        ReactiveFormsModule,
        TranslateModule,
        MatDialogModule,
        SettingsAboutSectionComponent,
        SettingsBackupSectionComponent,
        SettingsEpgSectionComponent,
        SettingsGeneralSectionComponent,
        SettingsPlaybackSectionComponent,
        SettingsRemoteControlSectionComponent,
        SettingsResetSectionComponent,
        SettingsSectionScrollDirective,
    ],
})
export class SettingsComponent implements OnInit, OnDestroy {
    private dialogService = inject(DialogService);
    public dataService = inject(DataService);
    private epgService = inject(EpgService);
    private formBuilder = inject(FormBuilder);
    private playlistsService = inject(PlaylistsService);
    private router = inject(Router);
    private settingsService = inject(SettingsService);
    private snackBar = inject(MatSnackBar);
    private store = inject(Store);
    private translate = inject(TranslateService);
    private matDialog = inject(MatDialog);
    private playlistBackupService = inject(PlaylistBackupService);
    private readonly databaseService = inject(DatabaseService);
    private readonly runtime = inject(RuntimeCapabilitiesService);
    private readonly epgBridge = inject(EpgRuntimeBridgeService);
    private readonly dialogData = inject<{ isDialog: boolean } | null>(
        MAT_DIALOG_DATA,
        { optional: true }
    );

    @Input() isDialog = this.dialogData?.isDialog ?? false;
    /** List with available languages as enum */
    readonly languageEnum = Language;

    /** List with allowed formats as enum */
    readonly streamFormatEnum = StreamFormat;

    /** Flag that indicates whether the app runs in electron environment */
    readonly isDesktop = this.runtime.isElectron;
    readonly supportsDesktopFileSave = this.runtime.supportsDesktopFileSave;
    readonly supportsEpg =
        this.epgBridge.supportsImport && this.epgBridge.supportsDataManagement;
    readonly supportsManagedExternalPlayers =
        this.runtime.supportsManagedExternalPlayers;
    readonly supportsExternalPlayerPathSettings =
        this.runtime.supportsExternalPlayerPathSettings;
    readonly supportsRemoteControl = this.runtime.supportsRemoteControl;
    readonly embeddedMpvSupport = signal<EmbeddedMpvSupport | null>(null);
    readonly supportsEmbeddedMpv = computed(
        () => this.isDesktop && !!this.embeddedMpvSupport()?.supported
    );

    readonly isPwa = this.runtime.isPwa;

    private readonly settingsCtx = inject(SettingsContextService);
    readonly activeSection = this.settingsCtx.activeSection;

    readonly osPlayers = computed(() => [
        ...(this.supportsEmbeddedMpv()
            ? [
                  {
                      id: VideoPlayer.EmbeddedMpv,
                      labelKey: 'SETTINGS.PLAYER_EMBEDDED_MPV',
                  },
              ]
            : []),
        ...(this.supportsManagedExternalPlayers
            ? SETTINGS_OS_PLAYER_OPTIONS
            : []),
    ]);

    /** Player options */
    readonly players = computed(() => [
        ...SETTINGS_EMBEDDED_PLAYER_OPTIONS,
        ...this.osPlayers(),
    ]);

    /** Current version of the app */
    version = '';

    /** Update message to show */
    updateMessage = '';

    /** EPG availability flag */
    epgAvailable$ = this.store.select(selectIsEpgAvailable);
    readonly playlists = this.store.selectSignal(selectAllPlaylistsMeta);

    readonly themeOptions = SETTINGS_THEME_OPTIONS;
    readonly coverSizeOptions = SETTINGS_COVER_SIZE_OPTIONS;
    readonly startupBehaviorOptions = SETTINGS_STARTUP_BEHAVIOR_OPTIONS;

    /** Settings form object */
    settingsForm = this.formBuilder.group({
        player: [VideoPlayer.VideoJs],
        ...(this.supportsEpg
            ? { epgUrl: new FormArray<FormControl<string | null>>([]) }
            : {}),
        streamFormat: StreamFormat.M3u8StreamFormat,
        openStreamOnDoubleClick: false,
        language: Language.ENGLISH,
        showCaptions: false,
        showDashboard: true,
        startupBehavior: StartupBehavior.FirstView,
        showExternalPlaybackBar: true,
        theme: Theme.SystemTheme,
        mpvPlayerPath: '',
        mpvPlayerArguments: '',
        mpvReuseInstance: false,
        vlcPlayerPath: '',
        vlcPlayerArguments: '',
        vlcReuseInstance: false,
        remoteControl: false,
        remoteControlPort: [
            8765,
            [
                Validators.required,
                Validators.min(1),
                Validators.max(65535),
                Validators.pattern(/^\d+$/),
            ],
        ],
        recordingFolder: '',
        coverSize: 'medium' as CoverSize,
        ...(this.supportsEpg
            ? { preferUploadedEpgOverXtream: false }
            : {}),
    });

    /** Form array with epg sources */
    epgUrl = this.settingsForm.get('epgUrl') as FormArray;

    /** Local IP addresses for remote control URL display */
    localIpAddresses = signal<string[]>([]);

    /** Currently visible QR code IP (null = none visible) */
    visibleQrCodeIp = signal<string | null>(null);
    readonly isRemovingAllPlaylists = signal(false);
    readonly isClearingEpgData = signal(false);
    readonly isExportingData = signal(false);
    readonly removeAllProgress = signal<DbOperationEvent | null>(null);

    private settingsStore = inject(SettingsStore);
    readonly sectionNavItems: SettingsSection[] = buildSettingsSectionNavItems(
        {
            supportsEpg: this.supportsEpg,
            supportsRemoteControl: this.supportsRemoteControl,
        }
    );

    readonly playlistDeleteSummary = computed<SettingsPlaylistDeleteSummary>(
        () => {
            const items = this.playlists();

            return {
                total: items.length,
                m3u: items.filter((item) => !item.serverUrl && !item.macAddress)
                    .length,
                xtream: items.filter((item) => Boolean(item.serverUrl)).length,
                stalker: items.filter((item) => Boolean(item.macAddress))
                    .length,
            };
        }
    );

    readonly canRemoveAllPlaylists = computed(
        () =>
            !this.isRemovingAllPlaylists() &&
            this.playlistDeleteSummary().total > 0
    );

    readonly removeAllProgressLabel = computed(() => {
        if (!this.isRemovingAllPlaylists()) {
            return null;
        }

        const progress = this.removeAllProgress();
        const current = progress?.current;
        const total = progress?.total;

        if (
            typeof current === 'number' &&
            typeof total === 'number' &&
            total > 0
        ) {
            return this.translate.instant('SETTINGS.REMOVE_ALL_PROGRESS', {
                current,
                total,
            });
        }

        return this.translate.instant('SETTINGS.REMOVE_ALL_IN_PROGRESS');
    });

    get sectionNav(): SettingsSection[] {
        return this.sectionNavItems.filter((section) => section.visible);
    }

    /**
     * Reads the config object from the browsers
     * storage (indexed db)
     */
    async ngOnInit(): Promise<void> {
        // Wait for settings to load before setting the form
        await this.settingsStore.loadSettings();
        this.setSettings();
        void this.loadEmbeddedMpvSupport();
        this.checkAppVersion();
        void this.fetchLocalIpAddresses();

        if (!this.isDialog) {
            this.settingsCtx.setSections(this.sectionNav);
        }
    }

    private async loadEmbeddedMpvSupport(): Promise<void> {
        if (!this.isDesktop) {
            this.embeddedMpvSupport.set({
                supported: false,
                platform: 'web',
                reason: 'Embedded MPV requires the Electron desktop build.',
            });
            return;
        }

        if (!window.electron?.getEmbeddedMpvSupport) {
            this.embeddedMpvSupport.set({
                supported: false,
                platform: window.electron.platform,
                reason: 'Embedded MPV support is not available in this build.',
            });
            return;
        }

        try {
            this.embeddedMpvSupport.set(
                await window.electron.getEmbeddedMpvSupport()
            );
        } catch (error) {
            this.embeddedMpvSupport.set({
                supported: false,
                platform: window.electron.platform,
                reason: error instanceof Error ? error.message : String(error),
            });
        }
    }

    ngOnDestroy(): void {
        this.settingsCtx.reset();
    }

    /**
     * Fetches local IP addresses for remote control URL display
     */
    async fetchLocalIpAddresses(): Promise<void> {
        if (
            this.supportsRemoteControl &&
            window.electron?.getLocalIpAddresses
        ) {
            const addresses = await window.electron.getLocalIpAddresses();
            this.localIpAddresses.set(addresses);
        }
    }

    /**
     * Toggle QR code visibility for a given IP address
     */
    toggleQrCode(ip: string): void {
        if (this.visibleQrCodeIp() === ip) {
            this.visibleQrCodeIp.set(null);
        } else {
            this.visibleQrCodeIp.set(ip);
        }
    }

    /**
     * Sets saved settings from the indexed db store
     */
    setSettings() {
        const currentSettings = this.settingsStore.getSettings();
        this.settingsForm.patchValue(currentSettings);

        if (this.supportsEpg && currentSettings.epgUrl) {
            this.epgUrl.clear();
            this.setEpgUrls(currentSettings.epgUrl);
        }
    }

    selectTheme(theme: Theme): void {
        if (this.settingsForm.value.theme === theme) {
            return;
        }

        this.settingsForm.patchValue({ theme });
        this.settingsForm.get('theme')?.markAsDirty();
        this.settingsForm.markAsDirty();
        this.settingsService.changeTheme(theme);
    }

    selectCoverSize(size: CoverSize): void {
        if (this.settingsForm.value.coverSize === size) {
            return;
        }

        this.settingsForm.patchValue({ coverSize: size });
        this.settingsForm.get('coverSize')?.markAsDirty();
        this.settingsForm.markAsDirty();
        this.settingsStore.updateSettings({ coverSize: size });
    }

    async selectRecordingFolder(): Promise<void> {
        if (
            !this.isDesktop ||
            !window.electron?.selectEmbeddedMpvRecordingFolder
        ) {
            return;
        }

        const folder = await window.electron.selectEmbeddedMpvRecordingFolder();
        if (!folder) {
            return;
        }

        this.settingsForm.patchValue({ recordingFolder: folder });
        this.settingsForm.get('recordingFolder')?.markAsDirty();
        this.settingsForm.markAsDirty();
    }

    /**
     * Sets the epg urls to the form array
     * @param epgUrls urls of the EPG sources
     */
    setEpgUrls(epgUrls: string[] | string): void {
        const urls = Array.isArray(epgUrls) ? epgUrls : [epgUrls];
        const filteredUrls = urls
            .map((url) => url.trim())
            .filter((url) => url !== '');

        filteredUrls.forEach((url) => {
            this.epgUrl.push(createEpgUrlControl(url));
        });
    }

    /**
     * Checks whether the latest version of the application
     * is used and updates the version message in the
     * settings UI
     */
    checkAppVersion(): void {
        this.settingsService
            .getAppVersion()
            .pipe(take(1))
            .subscribe((version) => this.showVersionInformation(version));
    }

    /**
     * Updates the message in settings UI about the used
     * version of the app
     * @param currentVersion current version of the application
     */
    showVersionInformation(currentVersion: string): void {
        const isOutdated = this.isCurrentVersionOutdated(currentVersion);

        if (isOutdated) {
            this.updateMessage = `${
                this.translate.instant(
                    'SETTINGS.NEW_VERSION_AVAILABLE'
                ) as string
            }: ${currentVersion}`;
        } else {
            this.updateMessage = this.translate.instant(
                'SETTINGS.LATEST_VERSION'
            );
        }
    }

    /**
     * Compares actual with latest version of the
     * application
     * @param latestVersion latest version
     * @returns returns true if an update is available
     */
    isCurrentVersionOutdated(latestVersion: string): boolean {
        this.version = this.dataService.getAppVersion();
        return this.settingsService.isVersionOutdated(
            this.version,
            latestVersion
        );
    }

    /**
     * Triggers on form submit and saves the config object to
     * the indexed db store
     */
    onSubmit(): void {
        const settings = this.createSettingsFromFormValue();

        this.settingsStore.updateSettings(settings).then(() => {
            this.applyChangedSettings();

            if (window.electron) {
                window.electron.updateSettings(settings);
            }

            if (this.supportsExternalPlayerPathSettings && window.electron) {
                window.electron.setMpvPlayerPath(settings.mpvPlayerPath);
                window.electron.setVlcPlayerPath(settings.vlcPlayerPath);
            }
        });
        if (this.isDialog) {
            this.matDialog.closeAll();
        }
    }

    private normalizeExternalPlayerPath(
        playerPath: string | null | undefined
    ): string {
        return playerPath?.trim() ?? '';
    }

    private createSettingsFromFormValue(): Settings {
        const currentSettings = this.settingsStore.getSettings();
        const value = this.settingsForm.value;
        const epgUrl = Array.isArray(value.epgUrl)
            ? value.epgUrl.filter(
                  (url): url is string => typeof url === 'string'
              )
            : (currentSettings.epgUrl ?? []);

        return {
            player: value.player ?? VideoPlayer.VideoJs,
            streamFormat: value.streamFormat ?? StreamFormat.M3u8StreamFormat,
            openStreamOnDoubleClick: value.openStreamOnDoubleClick ?? false,
            language: value.language ?? Language.ENGLISH,
            showCaptions: value.showCaptions ?? false,
            showDashboard: value.showDashboard ?? true,
            startupBehavior: value.startupBehavior ?? StartupBehavior.FirstView,
            showExternalPlaybackBar: value.showExternalPlaybackBar ?? true,
            theme: value.theme ?? Theme.SystemTheme,
            mpvPlayerPath: this.normalizeExternalPlayerPath(
                value.mpvPlayerPath
            ),
            mpvPlayerArguments: normalizeExternalPlayerArguments(
                value.mpvPlayerArguments
            ),
            mpvReuseInstance: value.mpvReuseInstance ?? false,
            vlcPlayerPath: this.normalizeExternalPlayerPath(
                value.vlcPlayerPath
            ),
            vlcPlayerArguments: normalizeExternalPlayerArguments(
                value.vlcPlayerArguments
            ),
            vlcReuseInstance: value.vlcReuseInstance ?? false,
            remoteControl: value.remoteControl ?? false,
            remoteControlPort: Number(value.remoteControlPort ?? 8765),
            recordingFolder: value.recordingFolder ?? '',
            coverSize: value.coverSize ?? 'medium',
            epgUrl,
            preferUploadedEpgOverXtream:
                value.preferUploadedEpgOverXtream ??
                currentSettings.preferUploadedEpgOverXtream ??
                false,
        };
    }

    /**
     * Applies the changed settings to the app
     */
    applyChangedSettings(): void {
        this.settingsForm.markAsPristine();
        if (this.supportsEpg) {
            let epgUrls = this.settingsForm.value.epgUrl;
            if (epgUrls) {
                if (!Array.isArray(epgUrls)) {
                    epgUrls = [epgUrls];
                }
                const validEpgUrls = epgUrls.filter(
                    (url): url is string =>
                        typeof url === 'string' && url !== ''
                );
                if (validEpgUrls.length > 0) {
                    // Fetch all EPG URLs at once
                    this.epgService.fetchEpg(validEpgUrls);
                }
            }
        }
        this.translate.use(
            this.settingsForm.value.language ?? Language.ENGLISH
        );
        this.settingsService.changeTheme(
            this.settingsForm.value.theme ?? Theme.SystemTheme
        );
        this.openSettingsSnackbar(
            this.translate.instant('SETTINGS.SETTINGS_SAVED')
        );
    }

    /**
     * Navigates back to the applications homepage
     */
    backToHome(): void {
        if (this.isDialog) {
            this.matDialog.closeAll();
        } else {
            this.router.navigateByUrl('/');
        }
    }

    /**
     * Force-fetch EPG for a single URL, bypassing the 12-hour freshness check.
     * The plain fetchEpg would short-circuit on fresh data and click the
     * refresh button would be a no-op — that's exactly not what the user
     * intends when clicking "Refresh".
     */
    refreshEpg(url: string): void {
        if (!this.epgBridge.supportsDataManagement || !url) {
            return;
        }
        void this.epgBridge.forceFetchEpg(url);
    }

    /**
     * Force-fetch every configured EPG URL sequentially. Empty fields are
     * skipped. Each URL flows through the normal progress panel so the user
     * gets visible per-URL feedback.
     */
    refreshAllEpg(): void {
        if (!this.epgBridge.supportsDataManagement) return;
        const urls = (this.epgUrl.value as string[])
            .map((url) => url?.trim())
            .filter((url): url is string => Boolean(url));
        urls.forEach((url) => void this.epgBridge.forceFetchEpg(url));
    }

    /**
     * Initializes new entry in form array for EPG URL
     */
    addEpgSource(): void {
        this.epgUrl.insert(this.epgUrl.length, createEpgUrlControl());
    }

    /**
     * Removes entry from form array for EPG URL
     * @param index index of the item to remove
     */
    removeEpgSource(index: number): void {
        this.epgUrl.removeAt(index);
        this.settingsForm.markAsDirty();
    }

    /**
     * Clears all EPG data from database and immediately re-fetches every
     * configured URL so the user isn't left staring at an empty state.
     * Tracks progress with `isClearingEpgData` so the UI can show a spinner
     * and block double-clicks, and surfaces failures via a dedicated snackbar.
     */
    clearEpgData(): void {
        this.dialogService.openConfirmDialog({
            title: this.translate.instant('SETTINGS.CLEAR_EPG_DIALOG.TITLE'),
            message: this.translate.instant(
                'SETTINGS.CLEAR_EPG_DIALOG.MESSAGE'
            ),
            onConfirm: async (): Promise<void> => {
                if (
                    !this.epgBridge.supportsDataManagement ||
                    this.isClearingEpgData()
                ) {
                    return;
                }

                this.isClearingEpgData.set(true);
                try {
                    const result = await this.epgBridge.clearEpgData();
                    if (result && result.success === false) {
                        throw new Error('Clear EPG returned success=false');
                    }
                    this.openSettingsSnackbar(
                        this.translate.instant('SETTINGS.EPG_DATA_CLEARED')
                    );
                    this.refreshAllEpg();
                } catch (error) {
                    console.error('Failed to clear EPG data:', error);
                    this.openSettingsSnackbar(
                        this.translate.instant('SETTINGS.EPG_DATA_CLEAR_FAILED')
                    );
                } finally {
                    this.isClearingEpgData.set(false);
                }
            },
        });
    }

    async exportData() {
        if (this.isExportingData()) {
            return;
        }

        this.isExportingData.set(true);

        // Let Angular paint the busy state before the backup build and native
        // save dialog handoff start.
        await this.waitForUiFeedbackFrame();

        try {
            const backup = await this.playlistBackupService.exportBackup();

            if (this.supportsDesktopFileSave && window.electron) {
                const savePath = await window.electron.saveFileDialog(
                    backup.defaultFileName,
                    [
                        {
                            name: 'JSON',
                            extensions: ['json'],
                        },
                    ]
                );

                if (!savePath) {
                    return;
                }

                await window.electron.writeFile(savePath, backup.json);
            } else {
                const blob = new Blob([backup.json], {
                    type: 'application/json',
                });
                const url = window.URL.createObjectURL(blob);
                const link = document.createElement('a');
                link.href = url;
                link.download = backup.defaultFileName;
                link.click();
                window.URL.revokeObjectURL(url);
            }

            this.openSettingsSnackbar('Playlist backup exported.');
        } catch (error) {
            console.error('Failed to export playlist backup:', error);
            this.openSettingsSnackbar('Playlist backup export failed.');
        } finally {
            this.isExportingData.set(false);
        }
    }

    importData() {
        const input = document.createElement('input');
        input.type = 'file';
        input.accept = 'application/json';

        input.addEventListener('change', async (event: Event) => {
            const target = event.target as HTMLInputElement;
            const file = target.files?.[0];

            if (file) {
                try {
                    const summary =
                        await this.playlistBackupService.importBackup(
                            await file.text()
                        );

                    if (summary.imported > 0 || summary.merged > 0) {
                        this.store.dispatch(
                            PlaylistActions.removeAllPlaylists()
                        );
                        this.store.dispatch(PlaylistActions.loadPlaylists());
                    }

                    this.setSettings();
                    this.openSettingsSnackbar(
                        this.buildBackupImportSummary(summary)
                    );

                    if (summary.errors.length > 0) {
                        console.error(
                            'Playlist backup import completed with issues:',
                            summary.errors
                        );
                    }
                } catch (error) {
                    console.error('Failed to import playlist backup:', error);
                    this.openSettingsSnackbar(
                        error instanceof Error
                            ? error.message
                            : this.translate.instant('SETTINGS.IMPORT_ERROR')
                    );
                }
            }
        });

        input.click();
    }

    private buildBackupImportSummary(
        summary: PlaylistBackupImportSummary
    ): string {
        return `Backup import finished: ${summary.imported} imported, ${summary.merged} merged, ${summary.skipped} skipped, ${summary.failed} failed.`;
    }

    private async waitForUiFeedbackFrame(): Promise<void> {
        if (typeof window.requestAnimationFrame !== 'function') {
            await Promise.resolve();
            return;
        }

        await new Promise<void>((resolve) => {
            window.requestAnimationFrame(() => resolve());
        });
    }

    removeAll(): void {
        if (!this.canRemoveAllPlaylists()) {
            return;
        }

        this.matDialog
            .open<
                SettingsDeleteAllPlaylistsDialogComponent,
                SettingsDeleteAllPlaylistsDialogData,
                boolean
            >(SettingsDeleteAllPlaylistsDialogComponent, {
                autoFocus: false,
                data: {
                    summary: this.playlistDeleteSummary(),
                },
                maxWidth: 'calc(100vw - 32px)',
                restoreFocus: true,
                width: '460px',
            })
            .afterClosed()
            .pipe(take(1))
            .subscribe((confirmed) => {
                if (confirmed) {
                    void this.removeAllConfirmed();
                }
            });
    }

    private async removeAllConfirmed(): Promise<void> {
        if (this.isRemovingAllPlaylists()) {
            return;
        }

        this.isRemovingAllPlaylists.set(true);
        this.removeAllProgress.set(null);

        await this.waitForUiFeedbackFrame();

        try {
            const deleted =
                this.isDesktop && window.electron
                    ? await this.deleteAllPlaylistsInElectron()
                    : await this.deleteAllPlaylistsInBrowser();

            if (!deleted) {
                throw new Error('Delete all playlists returned success=false');
            }

            this.store.dispatch(PlaylistActions.removeAllPlaylists());
            this.openSettingsSnackbar(
                this.translate.instant('SETTINGS.PLAYLISTS_REMOVED')
            );
        } catch (error) {
            console.error('Error removing playlists:', error);
            this.openSettingsSnackbar(
                this.translate.instant('SETTINGS.PLAYLISTS_REMOVE_FAILED')
            );
        } finally {
            this.removeAllProgress.set(null);
            this.isRemovingAllPlaylists.set(false);
        }
    }

    private async deleteAllPlaylistsInElectron(): Promise<boolean> {
        return this.databaseService.deleteAllPlaylists({
            operationId: this.databaseService.createOperationId(
                'settings-delete-all-playlists'
            ),
            onEvent: (event) => this.handleDeleteAllPlaylistsEvent(event),
        });
    }

    private async deleteAllPlaylistsInBrowser(): Promise<boolean> {
        await firstValueFrom(this.playlistsService.removeAll());
        return true;
    }

    private handleDeleteAllPlaylistsEvent(event: DbOperationEvent): void {
        this.removeAllProgress.set(event);
    }

    private openSettingsSnackbar(
        message: string,
        config: MatSnackBarConfig = {}
    ): void {
        this.snackBar.open(message, undefined, {
            duration: 2000,
            horizontalPosition: 'center',
            verticalPosition: 'bottom',
            panelClass: ['settings-snackbar'],
            ...config,
        });
    }
}
