import SwiftUI

enum LibraryLayout: String, CaseIterable, Identifiable {
    case grid
    case list

    var id: String { rawValue }
    var label: String { self == .grid ? "Kachelansicht" : "Listenansicht" }
    var systemImage: String { self == .grid ? "square.grid.2x2" : "list.bullet" }
}

struct LibraryListView: View {
    let items: [LibraryItem]
    var onRefresh: (() async -> Void)? = nil
    var dimDownloading: Bool = false
    let onSelect: (LibraryItem) -> Void

    var body: some View {
        #if os(iOS)
        List {
            // Identify by syncKey — see LibraryGridView comment.
            ForEach(items, id: \.syncKey) { item in
                LibraryListRow(item: item, dimDownloading: dimDownloading)
                    .contentShape(Rectangle())
                    .onTapGesture { onSelect(item) }
                    .listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
            }
        }
        .listStyle(.plain)
        .refreshable {
            await onRefresh?()
        }
        #else
        ScrollView {
            LazyVStack(spacing: 0) {
                ForEach(Array(items.enumerated()), id: \.element.syncKey) { idx, item in
                    LibraryListRow(item: item, dimDownloading: dimDownloading)
                        .contentShape(Rectangle())
                        .onTapGesture { onSelect(item) }
                    if idx < items.count - 1 {
                        Divider().padding(.leading, 76)
                    }
                }
            }
            .padding(.vertical, 4)
        }
        #endif
    }
}

struct LibraryListRow: View {
    @Environment(AppState.self) private var app
    let item: LibraryItem
    var dimDownloading: Bool = false

    var body: some View {
        HStack(spacing: 12) {
            ZStack {
                cover
                    .opacity(dimDownloading && isActivelyDownloading ? 0.55 : 1.0)
                if dimDownloading, case .downloading(let p) = app.downloads.state(for: item.downloadKey) {
                    LargeDownloadOverlay(progress: p, size: 40)
                }
            }
            VStack(alignment: .leading, spacing: 2) {
                Text(item.title)
                    .font(.headline)
                    .lineLimit(1)
                Text(item.author)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
                    .lineLimit(1)
                let fraction = app.progressFraction(itemId: item.id, episodeId: item.episodeId)
                if fraction > 0 && !isListened {
                    GeometryReader { geo in
                        ZStack(alignment: .leading) {
                            RoundedRectangle(cornerRadius: 1.5).fill(Color.gray.opacity(0.3))
                            RoundedRectangle(cornerRadius: 1.5).fill(Color.green)
                                .frame(width: max(2, geo.size.width * fraction))
                        }
                    }
                    .frame(height: 3)
                    .padding(.top, 2)
                    #if os(macOS)
                    .padding(.trailing, 40)
                    #endif
                }
            }
            .opacity(dimDownloading && isActivelyDownloading ? 0.55 : 1.0)
            Spacer(minLength: 8)
            #if os(macOS)
            if dimDownloading, app.downloads.downloadedBytes(for: item.downloadKey) > 0 {
                Text(formatBytes(app.downloads.downloadedBytes(for: item.downloadKey)))
                    .font(.caption.monospacedDigit())
                    .foregroundStyle(.secondary)
                    .opacity(dimDownloading && isActivelyDownloading ? 0.55 : 1.0)
            } else if item.durationSeconds > 0 {
                Text(formatDuration(item.durationSeconds))
                    .font(.caption.monospacedDigit())
                    .foregroundStyle(.secondary)
                    .opacity(dimDownloading && isActivelyDownloading ? 0.55 : 1.0)
            }
            #endif
            if isListened {
                Image(systemName: "checkmark.circle.fill")
                    .foregroundStyle(.white, .green)
                    .font(.title3)
            }
            if !(dimDownloading && isActivelyDownloading) {
                downloadStatus
                    #if os(macOS)
                    .frame(width: 28)
                    #endif
            }
        }
        #if os(macOS)
        .padding(.horizontal, 16)
        .padding(.vertical, 8)
        #endif
        .contextMenu { mediaItemContextMenu(for: item, app: app) }
    }

    private var isActivelyDownloading: Bool {
        if case .downloading = app.downloads.state(for: item.downloadKey) { return true }
        return false
    }

    private var isListened: Bool {
        app.progressCache[item.syncKey]?.isFinished ?? false
    }

    private var cover: some View {
        Group {
            if let url = app.client.coverURL(itemId: item.id) {
                AsyncImage(url: url) { phase in
                    switch phase {
                    case .empty:
                        Rectangle().fill(.quaternary)
                    case .success(let img):
                        img.resizable().aspectRatio(contentMode: .fill)
                    case .failure:
                        Rectangle().fill(.quaternary)
                            .overlay(Image(systemName: "book.closed").foregroundStyle(.secondary))
                    @unknown default:
                        Rectangle().fill(.quaternary)
                    }
                }
            } else {
                Rectangle().fill(.quaternary)
            }
        }
        #if os(iOS)
        .frame(width: 52, height: 52)
        .clipShape(RoundedRectangle(cornerRadius: 6))
        #else
        .frame(width: 48, height: 48)
        .clipShape(RoundedRectangle(cornerRadius: 4))
        #endif
    }

    @ViewBuilder
    private var downloadStatus: some View {
        let state = app.downloads.state(for: item.downloadKey)
        switch state {
        case .downloaded:
            // Down-arrow now signals "downloaded"; the checkmark is reserved
            // for the listened indicator that sits next to it.
            Image(systemName: "arrow.down.circle.fill")
                .foregroundStyle(.white, .green)
                .font(.title3)
        case .downloading(let p):
            DownloadProgressRing(progress: p)
                #if os(iOS)
                .frame(width: 22, height: 22)
                #else
                .frame(width: 24, height: 24)
                #endif
        case .failed:
            Image(systemName: "exclamationmark.circle.fill")
                .foregroundStyle(.white, .red)
                .font(.title3)
        case .notDownloaded:
            EmptyView()
        }
    }

    #if os(macOS)
    private func formatDuration(_ seconds: Double) -> String {
        guard seconds.isFinite, seconds > 0 else { return "" }
        let total = Int(seconds)
        let h = total / 3600
        let m = (total % 3600) / 60
        if h > 0 { return "\(h) h \(m) min" }
        return "\(m) min"
    }
    #endif
}
