import SwiftUI

enum LibraryFilter: Hashable {
    case home
    case library(String)
    case downloaded
    case history
}

/// One indexed (podcast, episode) pair used to make episodes searchable from the
/// library overview — without having to dive into each show first.
struct PodcastEpisodeMatch: Hashable {
    let podcast: LibraryItem
    let episode: PodcastEpisode

    var syncKey: String { "\(podcast.id)|\(episode.id)" }

    /// Synthesizes a `LibraryItem` so the cell/list views can render this
    /// episode the same way they render any other item: episode title up top,
    /// podcast name as the subtitle, podcast cover as the artwork.
    var asLibraryItem: LibraryItem {
        var item = LibraryItem(
            id: podcast.id,
            title: episode.title,
            author: podcast.title,
            durationSeconds: episode.durationSeconds > 0
                ? episode.durationSeconds
                : episode.audioFile.durationSeconds,
            audioFiles: [episode.audioFile]
        )
        item.mediaType = "podcast"
        item.episodeId = episode.id
        return item
    }
}

@Observable
@MainActor
final class LibraryViewModel {
    var libraries: [Library] = []
    var items: [LibraryItem] = []
    var isLoading: Bool = false
    var errorMessage: String?
    var selection: LibraryFilter?

    /// Episode index per library, populated lazily the first time the user
    /// types in the search bar of a podcast library. Episodes aren't part of
    /// `items` (those only hold podcast containers) so we have to load them
    /// explicitly. Kept in memory only — cleared whenever the library reloads.
    var episodeIndex: [String: [PodcastEpisodeMatch]] = [:]
    /// Library IDs currently being indexed. Prevents duplicate in-flight loads
    /// when the user types rapidly while the first request is still running.
    var episodeIndexLoading: Set<String> = []

    var isLoadingEpisodeIndex: Bool {
        !episodeIndexLoading.isEmpty
    }

    func loadLibraries(client: ABSClient) async {
        do {
            libraries = try await client.fetchLibraries()
            // Home is the new default landing screen — first library is only
            // used as fallback when there are zero libraries.
            if selection == nil {
                selection = .home
            }
        } catch {
            errorMessage = error.localizedDescription
        }
    }

    /// Fetches every podcast's episodes in the given library and caches them
    /// flat so the search field can match against episode titles too. No-ops
    /// when the index is already populated for this library.
    func loadEpisodeIndex(libraryId: String, client: ABSClient) async {
        guard episodeIndex[libraryId] == nil,
              !episodeIndexLoading.contains(libraryId) else { return }
        let podcasts = items.filter { $0.isPodcastContainer }
        guard !podcasts.isEmpty else {
            episodeIndex[libraryId] = []
            return
        }
        episodeIndexLoading.insert(libraryId)
        defer { episodeIndexLoading.remove(libraryId) }

        var collected: [PodcastEpisodeMatch] = []
        var anySuccess = false
        for p in podcasts {
            // Bail out if the user already navigated away — keeps a slow scan
            // from blocking later searches.
            guard selection == .library(libraryId) else { return }
            do {
                let (_, eps) = try await client.fetchEpisodes(podcastItemId: p.id)
                anySuccess = true
                for ep in eps {
                    collected.append(PodcastEpisodeMatch(podcast: p, episode: ep))
                }
            } catch {
                // Individual podcast fetch errors are ignored — the rest of
                // the library is still searchable.
            }
        }
        // Bei totalem Offline-Failure (kein einziger Fetch erfolgreich) NICHT
        // den Cache mit `[]` setzen — sonst wäre der Index "geladen aber leer"
        // und ein erneuter Suchversuch würde nichts mehr tun. Nil-lassen
        // erlaubt Retry beim nächsten Tippen.
        if anySuccess {
            episodeIndex[libraryId] = collected
        }
    }

    func episodeMatch(syncKey: String, in libraryId: String) -> PodcastEpisodeMatch? {
        episodeIndex[libraryId]?.first(where: { $0.syncKey == syncKey })
    }

    func loadItems(client: ABSClient, downloads: DownloadManager) async {
        guard let selection else { return }
        switch selection {
        case .home:
            // HomeView reads progressCache + recentItemsCache directly; no
            // library items to load into vm.items.
            items = []
            errorMessage = nil
        case .library(let id):
            // Reload of items invalidates the episode index — episodes are
            // tied to the previous snapshot of `items`. Auch das Loading-Flag
            // löschen damit ein nach-dem-Refresh neu getippter Suchbegriff
            // sofort einen Neu-Aufbau triggern kann (eine ggf. noch laufende
            // alte loadEpisodeIndex-Schleife läuft zu Ende und das Resultat
            // wird vom nächsten Trigger ohnehin überschrieben).
            episodeIndex.removeValue(forKey: id)
            episodeIndexLoading.remove(id)
            do {
                items = try await client.fetchItems(libraryId: id)
                errorMessage = nil
            } catch {
                errorMessage = error.localizedDescription
            }
        case .history:
            items = []
            errorMessage = nil
        case .downloaded:
            let completed = downloads.downloadedItems.values.map { di -> LibraryItem in
                let files: [AudioFile] = di.tracks.enumerated().map { idx, t in
                    AudioFile(
                        ino: t.ino,
                        filename: t.filename,
                        ext: "",
                        durationSeconds: t.durationSeconds,
                        index: idx
                    )
                }
                var li = LibraryItem(
                    id: di.itemId,
                    title: di.title,
                    author: di.author,
                    durationSeconds: di.durationSeconds,
                    audioFiles: files
                )
                if let episodeId = di.episodeId {
                    li.mediaType = "podcast"
                    li.episodeId = episodeId
                }
                return li
            }
            let inProgress = downloads.pendingItems.values.filter {
                downloads.downloadedItems[$0.downloadKey] == nil
            }
            items = (completed + Array(inProgress))
                .sorted { $0.title.localizedCaseInsensitiveCompare($1.title) == .orderedAscending }
            errorMessage = nil
        }
    }
}

struct MainView: View {
    @Environment(AppState.self) private var app
    @State private var vm = LibraryViewModel()
    @State private var navPath: [LibraryItem] = []
    @State private var librarySearchText: String = ""
    @AppStorage("libraryLayout") private var layoutRaw: String = LibraryLayout.grid.rawValue
    @AppStorage("historyEnabled") private var historyEnabled: Bool = false
    @State private var showFullHistory: Bool = false
    #if os(iOS)
    @State private var showSettings: Bool = false
    #endif

    private var layout: LibraryLayout {
        LibraryLayout(rawValue: layoutRaw) ?? .grid
    }

    var body: some View {
        // Modifiers like .task and .onChange cannot chain after a #if/#endif block
        // in a @ViewBuilder — wrap the conditional nav in a separate property instead.
        navigationRoot
            .task { await loadAll() }
            .onChange(of: vm.selection) { _, _ in
                navPath.removeAll()
                librarySearchText = ""
                Task { await loadAll() }
            }
            .onChange(of: librarySearchText) { _, newValue in
                // First keystroke in a podcast library kicks off the episode
                // index load (cached after that, so subsequent searches are
                // instant). Skipped for audiobook libraries — those don't
                // have episodes to scan.
                guard !newValue.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,
                      currentLibraryIsPodcast,
                      let libId = currentLibraryId else { return }
                Task { await vm.loadEpisodeIndex(libraryId: libId, client: app.client) }
            }
            .onChange(of: app.downloads.pendingItems.count) { _, _ in
                if vm.selection == .downloaded {
                    Task { await vm.loadItems(client: app.client, downloads: app.downloads) }
                }
            }
            .onChange(of: app.downloads.downloadedItems.count) { _, _ in
                if vm.selection == .downloaded {
                    Task { await vm.loadItems(client: app.client, downloads: app.downloads) }
                }
            }
            .safeAreaInset(edge: .bottom, spacing: 0) {
                PlayerBar()
                    .animation(.easeInOut(duration: 0.2), value: app.currentItem?.id)
                    .animation(.easeInOut(duration: 0.2), value: app.isPreparingPlayback)
            }
            .sheet(isPresented: $showFullHistory) {
                FullHistoryView()
                    .environment(app)
            }
            #if os(iOS)
            .alert(
                "Download fehlgeschlagen",
                isPresented: Binding(
                    get: { app.downloads.downloadFailureAlertTitle != nil },
                    set: { if !$0 { app.downloads.downloadFailureAlertTitle = nil } }
                )
            ) {
                Button("OK") { app.downloads.downloadFailureAlertTitle = nil }
            } message: {
                if let title = app.downloads.downloadFailureAlertTitle {
                    Text("\u{201E}\(title)\u{201C} konnte nicht heruntergeladen werden.")
                }
            }
            #endif
    }

    @ViewBuilder
    private var navigationRoot: some View {
        #if os(iOS)
        NavigationStack(path: $navPath) {
            detail
                .navigationTitle("")
                .navigationBarTitleDisplayMode(.inline)
                .toolbar {
                    ToolbarItem(placement: .topBarLeading) {
                        libraryMenu
                    }
                    ToolbarItem(placement: .topBarTrailing) {
                        Menu {
                            Picker("Ansicht", selection: $layoutRaw) {
                                ForEach(LibraryLayout.allCases) { l in
                                    Label(l.label, systemImage: l.systemImage).tag(l.rawValue)
                                }
                            }
                            if historyEnabled {
                                Divider()
                                Button {
                                    showFullHistory = true
                                } label: {
                                    Label(String(localized: "player.history_all"), systemImage: "clock.arrow.circlepath")
                                }
                            }
                            Divider()
                            Button {
                                showSettings = true
                            } label: {
                                Label("Einstellungen", systemImage: "gearshape")
                            }
                            Divider()
                            statusMenuSection
                        } label: {
                            Image(systemName: "ellipsis.circle")
                        }
                    }
                }
                .navigationDestination(for: LibraryItem.self) { podcast in
                    PodcastDetailView(podcast: podcast)
                }
        }
        .sheet(isPresented: $showSettings) {
            SettingsView()
                .environment(app)
        }
        #else
        NavigationSplitView {
            sidebar
        } detail: {
            NavigationStack(path: $navPath) {
                detail
                    .navigationDestination(for: LibraryItem.self) { podcast in
                        PodcastDetailView(podcast: podcast)
                    }
            }
        }
        #endif
    }

    private func loadAll() async {
        vm.items = []
        vm.isLoading = true
        defer { vm.isLoading = false }

        await vm.loadLibraries(client: app.client)
        if vm.selection != .history {
            await vm.loadItems(client: app.client, downloads: app.downloads)
        }
        await app.refreshProgressCache()
    }

    private func handleSelect(_ item: LibraryItem) {
        if item.isPodcastEpisode {
            // Synthetic episode result from library-wide podcast search.
            // Prefer the in-memory index (no extra round-trip); fall back to
            // re-fetching via the Home/Recents path if the index expired.
            if let libId = currentLibraryId,
               let match = vm.episodeMatch(syncKey: item.syncKey, in: libId) {
                Task { await app.play(podcast: match.podcast, episode: match.episode) }
            } else {
                Task { await app.playFromRecents(item) }
            }
        } else if item.isPodcastContainer {
            navPath.append(item)
        } else {
            Task { await app.play(item: item) }
        }
    }

    private var currentLibraryId: String? {
        if case .library(let id) = vm.selection { return id }
        return nil
    }

    private var currentLibraryIsPodcast: Bool {
        guard let id = currentLibraryId else { return false }
        if let mt = vm.libraries.first(where: { $0.id == id })?.mediaType {
            return mt == "podcast"
        }
        // Fallback: `vm.libraries` ist noch leer (User tippt direkt nach
        // App-Start, bevor `loadLibraries()` durch ist). Wir leiten den Typ
        // aus den bereits geladenen Items ab — sobald die Library Items
        // hat die Podcast-Container sind, ist es eine Podcast-Library.
        return vm.items.contains { $0.isPodcastContainer }
    }

    // MARK: - macOS sidebar

    #if os(macOS)
    private var sidebar: some View {
        List(selection: $vm.selection) {
            Section {
                Label("Home", systemImage: "house.fill")
                    .tag(LibraryFilter.home)
            }
            Section(String(localized: "sidebar.libraries")) {
                ForEach(vm.libraries) { lib in
                    Label(lib.name, systemImage: "books.vertical")
                        .tag(LibraryFilter.library(lib.id))
                }
            }
            Section(String(localized: "sidebar.offline")) {
                Label(String(localized: "nav.downloaded"), systemImage: "arrow.down.circle.fill")
                    .tag(LibraryFilter.downloaded)
            }
            if historyEnabled {
                Section(String(localized: "nav.history")) {
                    Label(String(localized: "sidebar.history"), systemImage: "clock.arrow.circlepath")
                        .tag(LibraryFilter.history)
                }
            }
        }
        .listStyle(.sidebar)
        .navigationTitle(String(localized: "sidebar.app_title"))
        .safeAreaInset(edge: .bottom) {
            sidebarFooter
        }
    }

    private var sidebarFooter: some View {
        VStack(spacing: 0) {
            Divider()
            VStack(spacing: 0) {
                HStack(spacing: 6) {
                    Circle()
                        .fill(app.network.isOnline ? Color.green : Color.orange)
                        .frame(width: 6, height: 6)
                    Text(app.network.isOnline
                         ? String(localized: "sidebar.status_online")
                         : String(localized: "sidebar.status_offline"))
                        .font(.caption2)
                        .foregroundStyle(.tertiary)
                    if app.sync.queuedCount > 0 {
                        Text("· \(app.sync.queuedCount)")
                            .font(.caption2)
                            .foregroundStyle(.tertiary)
                    }
                    Spacer()
                }
                .padding(.bottom, 4)
                HStack(spacing: 6) {
                    Image(systemName: "person.circle")
                        .font(.caption2)
                        .foregroundStyle(.secondary)
                    Text(app.auth.username)
                        .font(.caption2)
                        .foregroundStyle(.secondary)
                        .lineLimit(1)
                    Spacer()
                    Button {
                        app.stopPlayback()
                        app.auth.logout()
                    } label: {
                        Image(systemName: "rectangle.portrait.and.arrow.right")
                            .font(.caption2)
                            .foregroundStyle(.secondary)
                    }
                    .buttonStyle(.borderless)
                    .help(String(localized: "settings.logout"))
                }
            }
            .padding(.horizontal, 12)
            .padding(.top, 8)
            .padding(.bottom, 10)
            // Reserve space for PlayerBar — macOS safeAreaInset doesn't propagate into
            // nested safeAreaInset overlays, so we add explicit spacing here.
            if app.currentItem != nil || app.isPreparingPlayback {
                Color.clear.frame(height: 78)
            }
        }
    }

    private var historyDetailContent: some View {
        List {
            ForEach(app.history.entries) { entry in
                let isCurrent = entry.itemId == app.currentItem?.id &&
                                entry.episodeId == app.currentItem?.episodeId
                Button {
                    Task { await app.playFromHistory(entry) }
                } label: {
                    HStack(spacing: 10) {
                        VStack(alignment: .leading, spacing: 3) {
                            Text(entry.itemTitle)
                                .font(.subheadline.bold())
                            HStack(spacing: 4) {
                                if let ch = entry.chapterTitle {
                                    Text(ch).font(.caption).foregroundStyle(.secondary)
                                    Text("·").font(.caption).foregroundStyle(.secondary)
                                }
                                Text(historyFormatTime(entry.position))
                                    .font(.caption.monospacedDigit())
                                    .foregroundStyle(.secondary)
                            }
                            Text(historyRelativeTime(entry.timestamp))
                                .font(.caption2).foregroundStyle(.tertiary)
                        }
                        Spacer()
                        if !isCurrent {
                            Text(String(localized: "history.other_item"))
                                .font(.caption2).foregroundStyle(.tertiary)
                        }
                    }
                    .contentShape(Rectangle())
                }
                .buttonStyle(.plain)
            }
            if !app.history.entries.isEmpty {
                Section {
                    Button(role: .destructive) {
                        app.history.clear()
                    } label: {
                        Text(String(localized: "history.clear"))
                            .frame(maxWidth: .infinity, alignment: .center)
                    }
                }
            }
        }
        .listStyle(.plain)
        .overlay {
            if app.history.entries.isEmpty {
                ContentUnavailableView(
                    String(localized: "history.empty"),
                    systemImage: "clock.arrow.circlepath",
                    description: Text(String(localized: "history.empty_desc"))
                )
            }
        }
    }

    private func historyFormatTime(_ seconds: Double) -> String {
        guard seconds.isFinite, seconds >= 0 else { return "0:00" }
        let total = Int(seconds)
        let h = total / 3600, m = (total % 3600) / 60, s = total % 60
        return h > 0 ? String(format: "%d:%02d:%02d", h, m, s) : String(format: "%d:%02d", m, s)
    }

    private func historyRelativeTime(_ date: Date) -> String {
        let diff = Int(-date.timeIntervalSinceNow)
        if diff < 60 { return String(localized: "history.just_now") }
        if diff < 3600 { return String(format: String(localized: "history.minutes_ago"), diff / 60) }
        if diff < 86400 { return String(format: String(localized: "history.hours_ago"), diff / 3600) }
        return String(format: String(localized: "history.days_ago"), diff / 86400)
    }
    #endif

    // MARK: - Detail content

    @ViewBuilder
    private var detail: some View {
        #if os(macOS)
        if vm.selection == .home {
            HomeView(libraries: vm.libraries)
                .navigationTitle("Home")
                .toolbar {
                    // Same Kachel/Liste picker the library view has, so the
                    // shared `libraryLayout` setting can be toggled from Home
                    // too. Otherwise the user would land here with no UI
                    // affordance to switch into Listenansicht.
                    ToolbarItem(placement: .primaryAction) {
                        Picker("Ansicht", selection: $layoutRaw) {
                            ForEach(LibraryLayout.allCases) { l in
                                Image(systemName: l.systemImage)
                                    .help(l.label)
                                    .tag(l.rawValue)
                            }
                        }
                        .pickerStyle(.segmented)
                        .help("Zwischen Kachel- und Listenansicht wechseln")
                    }
                }
        } else if vm.selection == .history {
            historyDetailContent
                .navigationTitle(String(localized: "sidebar.history"))
        } else {
            libraryContent
        }
        #else
        if vm.selection == .home {
            HomeView(libraries: vm.libraries)
        } else {
            libraryContent
        }
        #endif
    }

    private var filteredItems: [LibraryItem] {
        let q = librarySearchText.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !q.isEmpty else { return vm.items }
        let containerMatches = vm.items.filter { item in
            item.title.localizedCaseInsensitiveContains(q)
                || item.author.localizedCaseInsensitiveContains(q)
        }
        // For podcast libraries, also surface matching episodes from across
        // the entire library — the user shouldn't have to dive into each show
        // first. Episode rows render with the show name as their subtitle.
        guard currentLibraryIsPodcast, let libId = currentLibraryId else {
            return containerMatches
        }
        let episodeMatches = (vm.episodeIndex[libId] ?? [])
            .filter { $0.episode.title.localizedCaseInsensitiveContains(q) }
            .map { $0.asLibraryItem }
        return containerMatches + episodeMatches
    }

    private var libraryContent: some View {
        ZStack {
            if vm.isLoading && vm.items.isEmpty {
                ProgressView("Lade Bibliothek …")
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .transition(.opacity)
            } else if let err = vm.errorMessage, vm.items.isEmpty {
                ContentUnavailableView("Fehler", systemImage: "exclamationmark.triangle", description: Text(err))
                    .transition(.opacity)
            } else if vm.items.isEmpty {
                ContentUnavailableView("Keine Hörbücher", systemImage: "books.vertical", description: Text("Diese Auswahl enthält noch keine Hörbücher."))
                    .transition(.opacity)
            } else if filteredItems.isEmpty {
                if vm.isLoadingEpisodeIndex {
                    VStack(spacing: 10) {
                        ProgressView()
                        Text("Folgen werden durchsucht …")
                            .font(.callout)
                            .foregroundStyle(.secondary)
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                } else {
                    ContentUnavailableView.search(text: librarySearchText)
                        .transition(.opacity)
                }
            } else {
                VStack(spacing: 0) {
                    if vm.isLoadingEpisodeIndex {
                        HStack(spacing: 8) {
                            ProgressView().controlSize(.small)
                            Text("Folgen werden durchsucht …")
                                .font(.caption)
                                .foregroundStyle(.secondary)
                            Spacer()
                        }
                        .padding(.horizontal, 16)
                        .padding(.vertical, 6)
                    }
                    libraryGridOrList
                }
                .transition(.opacity)
            }
        }
        .animation(.easeInOut(duration: 0.2), value: vm.isLoading)
        .animation(.easeInOut(duration: 0.2), value: vm.items.isEmpty)
        .animation(.easeInOut(duration: 0.15), value: filteredItems.isEmpty)
        .animation(.easeInOut(duration: 0.15), value: vm.isLoadingEpisodeIndex)
        .searchable(text: $librarySearchText, placement: .automatic, prompt: searchPrompt)
    }

    private var searchPrompt: String {
        switch vm.selection {
        case .library(let id):
            let mediaType = vm.libraries.first(where: { $0.id == id })?.mediaType
            return mediaType == "podcast" ? "Podcasts & Folgen durchsuchen" : "Hörbücher durchsuchen"
        case .downloaded:
            return "Downloads durchsuchen"
        default:
            return "Suchen"
        }
    }

    @ViewBuilder
    private var libraryGridOrList: some View {
        Group {
            let isDownloaded = vm.selection == .downloaded
            switch layout {
            case .grid:
                LibraryGridView(items: filteredItems, onRefresh: loadAll, dimDownloading: isDownloaded) { handleSelect($0) }
            case .list:
                LibraryListView(items: filteredItems, onRefresh: loadAll, dimDownloading: isDownloaded) { handleSelect($0) }
            }
        }
        #if os(macOS)
        .navigationTitle(currentTitle)
        .toolbar {
            ToolbarItem(placement: .primaryAction) {
                Button {
                    Task { await loadAll() }
                } label: {
                    if vm.isLoading {
                        ProgressView().controlSize(.small)
                    } else {
                        Image(systemName: "arrow.clockwise")
                    }
                }
                .help("Bibliothek, Cover und Hörfortschritte neu laden")
                .disabled(vm.isLoading)
            }
            ToolbarItem(placement: .primaryAction) {
                Picker("Ansicht", selection: $layoutRaw) {
                    ForEach(LibraryLayout.allCases) { l in
                        Image(systemName: l.systemImage)
                            .help(l.label)
                            .tag(l.rawValue)
                    }
                }
                .pickerStyle(.segmented)
                .help("Zwischen Kachel- und Listenansicht wechseln")
            }
        }
        #endif
    }

    // MARK: - iOS-only helpers

    #if os(iOS)
    private var libraryMenu: some View {
        Menu {
            Picker("Bibliothek", selection: Binding(
                get: { vm.selection ?? .home },
                set: { vm.selection = $0 }
            )) {
                Label("Home", systemImage: "house.fill")
                    .tag(LibraryFilter.home)
                Section("Bibliotheken") {
                    ForEach(vm.libraries) { lib in
                        Label(lib.name, systemImage: "books.vertical")
                            .tag(LibraryFilter.library(lib.id))
                    }
                }
                Section("Offline") {
                    Label("Heruntergeladen", systemImage: "arrow.down.circle.fill")
                        .tag(LibraryFilter.downloaded)
                }
            }
        } label: {
            HStack(spacing: 4) {
                Image(systemName: selectionIcon)
                Text(currentTitle)
                    .lineLimit(1)
                    .font(.headline)
                Image(systemName: "chevron.down")
                    .font(.caption)
            }
            .foregroundStyle(.primary)
        }
    }

    @ViewBuilder
    private var statusMenuSection: some View {
        Section(app.auth.username.isEmpty ? "Status" : "Angemeldet als \(app.auth.username)") {
            Label(app.network.isOnline ? "Online" : "Offline",
                  systemImage: app.network.isOnline ? "wifi" : "wifi.slash")
            if app.sync.queuedCount > 0 {
                Label("\(app.sync.queuedCount) Synchronisationen wartend",
                      systemImage: "arrow.triangle.2.circlepath")
            }
        }
    }

    private var selectionIcon: String {
        switch vm.selection {
        case .home:       return "house.fill"
        case .downloaded: return "arrow.down.circle.fill"
        case .history:    return "clock.arrow.circlepath"
        default:          return "books.vertical"
        }
    }
    #endif

    // MARK: - Shared helpers

    private var currentTitle: String {
        switch vm.selection {
        case .home:
            return "Home"
        case .library(let id):
            return vm.libraries.first(where: { $0.id == id })?.name ?? "Bibliothek"
        case .downloaded:
            return "Heruntergeladen"
        case .history:
            return String(localized: "sidebar.history")
        case .none:
            return "Bibliothek"
        }
    }
}
