//
//  DownloadRowView.swift
//  Yattee
//
//  Row view for displaying a download item.
//

import SwiftUI

#if !os(tvOS)
/// Row view for displaying a download item.
/// Automatically handles DeArrow integration.
/// For completed downloads, uses VideoRowView with tap zone support (thumbnail plays, text opens info).
/// For active downloads, shows custom progress UI with no tap actions.
struct DownloadRowView: View {
    @Environment(\.appEnvironment) private var appEnvironment

    let download: Download
    let isActive: Bool

    // Queue context (optional, enables auto-play when provided)
    var queueSource: QueueSource? = nil
    var sourceLabel: String? = nil
    var videoList: [Video]? = nil
    var videoIndex: Int? = nil
    var loadMoreVideos: LoadMoreVideosCallback? = nil

    // Cache watch progress to avoid CoreData fetches on every re-render
    @State private var cachedWatchProgress: Double?
    @State private var cachedWatchedSeconds: TimeInterval?
    @State private var hasLoadedWatchData = false

    private var video: Video {
        download.toVideo(downloadsDirectory: appEnvironment?.downloadManager.downloadsDirectory())
    }

    /// Watch progress for this video (0.0 to 1.0), or nil if not watched.
    /// Uses cached value to avoid CoreData fetch on every re-render.
    private var watchProgress: Double? {
        guard !isActive else { return nil }
        return cachedWatchProgress
    }

    /// Watch position in seconds for resume functionality.
    /// Uses cached value to avoid CoreData fetch on every re-render.
    private var watchedSeconds: TimeInterval? {
        guard !isActive else { return nil }
        return cachedWatchedSeconds
    }

    /// Loads watch data from CoreData once on appear.
    private func loadWatchDataIfNeeded() {
        guard !hasLoadedWatchData, !isActive else { return }
        hasLoadedWatchData = true

        guard let dataManager = appEnvironment?.dataManager else { return }

        // Load watch progress
        if let entry = dataManager.watchEntry(for: video.id.videoID) {
            let progress = entry.progress
            cachedWatchProgress = progress > 0 && progress < 1 ? progress : nil
        }

        // Load watched seconds
        cachedWatchedSeconds = dataManager.watchProgress(for: video.id.videoID)
    }

    /// Metadata text for completed downloads (file size + download date)
    private var downloadMetadata: String {
        let sizeText = formatBytes(download.totalBytes)
        
        if let completedAt = download.completedAt {
            let dateText = RelativeDateFormatter.string(for: completedAt)
            return "\(sizeText) • \(dateText)"
        }
        
        return sizeText
    }

    var body: some View {
        if isActive {
            // Active downloads: custom row with progress indicators, no tap actions
            activeDownloadContent
                .contextMenu {
                    activeDownloadMenuItems
                }
        } else {
            // Completed downloads: use VideoRowView with tap zones (thumbnail plays, text opens info)
            VideoRowView(
                video: video,
                style: .regular,
                watchProgress: watchProgress,
                customMetadata: downloadMetadata
            )
            .tappableVideo(
                video,
                startTime: watchedSeconds,
                queueSource: queueSource,
                sourceLabel: sourceLabel,
                videoList: videoList,
                videoIndex: videoIndex,
                loadMoreVideos: loadMoreVideos
            )
            .videoContextMenu(
                video: video,
                customActions: [
                    VideoContextAction(
                        String(localized: "downloads.delete"),
                        systemImage: "trash",
                        role: .destructive,
                        action: {
                            Task { await appEnvironment?.downloadManager.delete(download) }
                        }
                    )
                ],
                context: .downloads
            )
            .onAppear {
                loadWatchDataIfNeeded()
            }
        }
    }

    /// Menu items for an in-progress download: pause/resume/retry plus cancel.
    /// The `.downloads` video context menu hides the built-in cancel item, and swipe
    /// actions are iOS-only, so this is the only cancel affordance on macOS.
    @ViewBuilder
    private var activeDownloadMenuItems: some View {
        switch download.status {
        case .queued, .downloading:
            Button {
                Task { await appEnvironment?.downloadManager.pause(download) }
            } label: {
                Label(String(localized: "downloads.pause"), systemImage: "pause.fill")
            }

        case .paused:
            Button {
                Task { await appEnvironment?.downloadManager.resume(download) }
            } label: {
                Label(String(localized: "downloads.resume"), systemImage: "play.fill")
            }

        case .failed:
            Button {
                Task { await appEnvironment?.downloadManager.resume(download) }
            } label: {
                Label(String(localized: "downloads.retry"), systemImage: "arrow.clockwise")
            }

        case .completed:
            EmptyView()
        }

        Button(role: .destructive) {
            Task { await appEnvironment?.downloadManager.cancel(download) }
        } label: {
            Label(String(localized: "downloads.cancel"), systemImage: "xmark.circle")
        }
    }

    private var activeDownloadContent: some View {
        HStack(spacing: 12) {
            // Thumbnail (download status shown automatically)
            DeArrowVideoThumbnail(
                video: video,
                duration: video.formattedDuration
            )
            .frame(width: 120, height: 68)

            // Info
            VStack(alignment: .leading, spacing: 2) {
                Text(video.displayTitle(using: appEnvironment?.deArrowBrandingProvider))
                    .font(.subheadline)
                    .lineLimit(2)

                Text(download.channelName)
                    .font(.caption)
                    .foregroundStyle(.secondary)

                if isActive {
                    activeDownloadStatusView
                } else {
                    Text(formatBytes(download.totalBytes))
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }

            Spacer()
        }
        .contentShape(Rectangle())
    }

    #if os(iOS)
    private var isWaitingForWiFi: Bool {
        guard let settings = appEnvironment?.downloadSettings,
              let connectivity = appEnvironment?.connectivityMonitor else {
            return false
        }
        return !settings.allowCellularDownloads && connectivity.isCellular
    }
    #endif

    @ViewBuilder
    private var activeDownloadStatusView: some View {
        switch download.status {
        case .queued:
            #if os(iOS)
            if isWaitingForWiFi {
                Label(String(localized: "downloads.status.waitingForWiFi"), systemImage: "wifi")
                    .font(.caption)
                    .foregroundStyle(.orange)
            } else {
                Label(String(localized: "downloads.status.queued"), systemImage: "clock")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
            #else
            Label(String(localized: "downloads.status.queued"), systemImage: "clock")
                .font(.caption)
                .foregroundStyle(.secondary)
            #endif

        case .downloading:
            #if os(iOS)
            if isWaitingForWiFi {
                waitingForWiFiProgressView
            } else {
                streamProgressView
            }
            #else
            streamProgressView
            #endif

        case .paused:
            Label(String(localized: "downloads.status.paused"), systemImage: "pause.circle")
                .font(.caption)
                .foregroundStyle(.orange)

        case .failed:
            Label(String(localized: "downloads.status.failed"), systemImage: "exclamationmark.circle")
                .font(.caption)
                .foregroundStyle(.red)

        case .completed:
            EmptyView()
        }
    }

    #if os(iOS)
    @ViewBuilder
    private var waitingForWiFiProgressView: some View {
        let hasAudio = download.audioStreamURL != nil
        let hasCaption = download.captionURL != nil

        VStack(alignment: .leading, spacing: 3) {
            // Video progress with waiting indicator
            waitingProgressRow(
                icon: "film",
                progress: download.videoProgress,
                isCompleted: download.videoProgress >= 1.0
            )

            // Audio progress (if applicable)
            if hasAudio {
                waitingProgressRow(
                    icon: "waveform",
                    progress: download.audioProgress,
                    isCompleted: download.audioProgress >= 1.0
                )
            }

            // Caption progress (if applicable)
            if hasCaption {
                waitingProgressRow(
                    icon: "captions.bubble",
                    progress: download.captionProgress,
                    isCompleted: download.captionProgress >= 1.0
                )
            }

            // Waiting for WiFi label
            Label(String(localized: "downloads.status.waitingForWiFi"), systemImage: "wifi")
                .font(.caption2)
                .foregroundStyle(.orange)
        }
    }

    @ViewBuilder
    private func waitingProgressRow(
        icon: String,
        progress: Double,
        isCompleted: Bool
    ) -> some View {
        HStack(spacing: 4) {
            Image(systemName: icon)
                .font(.caption2)
                .foregroundStyle(.secondary)
                .frame(width: 16)

            if isCompleted {
                Image(systemName: "checkmark.circle.fill")
                    .font(.caption2)
                    .foregroundStyle(.green)
            } else {
                ProgressView(value: progress)
                    .frame(width: 50)
                    .tint(.orange)

                Text("\(Int(progress * 100))%")
                    .font(.caption2.monospacedDigit())
                    .foregroundStyle(.secondary)
                    .fixedSize()
            }
        }
    }
    #endif

    @ViewBuilder
    private var streamProgressView: some View {
        let hasAudio = download.audioStreamURL != nil
        let hasCaption = download.captionURL != nil

        VStack(alignment: .leading, spacing: 3) {
            // Video progress
            streamProgressRow(
                icon: "film",
                progress: download.videoProgress,
                speed: download.videoDownloadSpeed,
                isActive: download.videoProgress < 1.0,
                isCompleted: download.videoProgress >= 1.0,
                isSizeUnknown: download.videoSizeUnknown,
                downloadedBytes: download.videoDownloadedBytes
            )

            // Audio progress (if applicable)
            if hasAudio {
                streamProgressRow(
                    icon: "waveform",
                    progress: download.audioProgress,
                    speed: download.audioDownloadSpeed,
                    isActive: download.audioProgress < 1.0,
                    isCompleted: download.audioProgress >= 1.0,
                    isSizeUnknown: download.audioSizeUnknown,
                    downloadedBytes: download.audioDownloadedBytes
                )
            }

            // Caption progress (if applicable)
            if hasCaption {
                streamProgressRow(
                    icon: "captions.bubble",
                    progress: download.captionProgress,
                    speed: download.captionDownloadSpeed,
                    isActive: download.captionProgress < 1.0,
                    isCompleted: download.captionProgress >= 1.0,
                    isSizeUnknown: download.captionSizeUnknown,
                    downloadedBytes: download.captionDownloadedBytes
                )
            }
        }
    }

    @ViewBuilder
    private func streamProgressRow(
        icon: String,
        progress: Double,
        speed: Int64,
        isActive: Bool,
        isCompleted: Bool,
        isSizeUnknown: Bool = false,
        downloadedBytes: Int64 = 0
    ) -> some View {
        HStack(spacing: 4) {
            Image(systemName: icon)
                .font(.caption2)
                .foregroundStyle(.secondary)
                .frame(width: 16)

            if isCompleted {
                Image(systemName: "checkmark.circle.fill")
                    .font(.caption2)
                    .foregroundStyle(.green)
            } else if isSizeUnknown {
                // Indeterminate: show bytes downloaded instead of percentage
                Text(formatBytes(downloadedBytes))
                    .font(.caption2.monospacedDigit())
                    .foregroundStyle(.secondary)
                    .fixedSize()

                if isActive && speed > 0 {
                    Text(formatSpeed(speed))
                        .font(.caption2.monospacedDigit())
                        .foregroundStyle(.secondary)
                        .fixedSize()
                }
            } else {
                ProgressView(value: progress)
                    .frame(width: 50)

                Text("\(Int(progress * 100))%")
                    .font(.caption2.monospacedDigit())
                    .foregroundStyle(.secondary)
                    .fixedSize()

                if isActive && speed > 0 {
                    Text(formatSpeed(speed))
                        .font(.caption2.monospacedDigit())
                        .foregroundStyle(.secondary)
                        .fixedSize()
                }
            }
        }
    }

    private func formatBytes(_ bytes: Int64) -> String {
        let formatter = ByteCountFormatter()
        formatter.countStyle = .file
        return formatter.string(fromByteCount: bytes)
    }

    private func formatSpeed(_ bytesPerSecond: Int64) -> String {
        let formatter = ByteCountFormatter()
        formatter.countStyle = .file
        formatter.allowedUnits = [.useKB, .useMB, .useGB]
        return formatter.string(fromByteCount: bytesPerSecond) + "/s"
    }
}

// MARK: - Preview
// Note: Preview requires a Video object for Download initialization.
// See DownloadsView.swift for usage examples.
#endif
