import Nuke
import NukeUI
import SwiftUI
import Utilities

/// Downloads a remote image
///  use fallbackID to pick one of 3 placeholders, id is to ensure the image picked is stable across screens. ie, clip.id, playlist.id, user.id
///  If we want to downsample an image for increased loading speed and UI performance, we can manually pass a small requested size in
public struct RemoteImage: View, Equatable {
    let urlString: String?
    let fallbackId: String?
    let progressViewColor: Color
    let backgroundColor: Color
    let contentMode: ContentMode
    let requestedSize: CGSize?

    private var url: URL? {
        if let urlString {
            URL(string: urlString)
        } else {
            nil
        }
    }

    public init(
        url: String?,
        fallbackId: String?,
        progressViewColor: Color = .SemanticV1.textPrimary,
        backgroundColor: Color = .SemanticV1.backgroundTertiary,
        contentMode: ContentMode = .fill,
        requestedSize: CGSize? = nil
    ) {
        self.urlString = url
        self.fallbackId = fallbackId
        self.progressViewColor = progressViewColor
        self.backgroundColor = backgroundColor
        self.contentMode = contentMode
        self.requestedSize = requestedSize
    }

    public var body: some View {
        Color.clear
            .overlay {
                if let url {
                    content(url: url)
                }
            }
            .background(background)
    }

    @ViewBuilder
    private func content(url: URL) -> some View {
        if let requestedSize {
            LazyImage(
                request: .init(
                    url: url,
                    processors: [ImageProcessors.Resize(size: requestedSize)]
                ),
                content: lazyImageContent(_:)
            )
        } else {
            LazyImage(
                url: url,
                content: lazyImageContent(_:)
            )
        }
    }

    @ViewBuilder
    private func lazyImageContent(_ state: any LazyImageState) -> some View {
        if let image = state.image {
            image
                .resizable()
                .aspectRatio(contentMode: contentMode)
        } else if state.isLoading {
            GradientSpinner(size: .large, color: progressViewColor)
        } else if let fallbackId {
            defaultImage(for: fallbackId)
                .resizable()
                .aspectRatio(contentMode: contentMode)
        } else {
            background
        }
    }

    @ViewBuilder
    private var background: some View {
        if let urlString, !urlString.isEmpty {
            if contentMode == .fit {
                RemoteAverageColorView(imageUrl: urlString)
            } else {
                backgroundColor
            }
        } else {
            backgroundColor
        }
    }
}

#Preview {
    RemoteImage(url: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQWnaXjW9mSNXAPFaf_KYrmtuw-0JvFYDXqVXvmqqUpkL8inRxTOmvoeLyiYyHRxQtnhsAfl9pX_9gBeOPtWVUuZRaUAXt60f16coIqvtVLhg&s=10", fallbackId: nil)
}
