import SwiftUI

/**
 It'd be really easy to use .task{} here, but as we're supporting iOS 14 we need a minor view model as a conduit
 */

fileprivate class URLImageViewModel: ObservableObject {
    let imageLoader = ImageLoader()
    @Published var image: UIImage?
    
    
    init(urlRequest: URLRequest) {
        Task {
            let image = await loadImage(urlRequest: urlRequest)
            DispatchQueue.main.async {
                self.image = image
            }
        }
    }
    
    @MainActor func loadImage(urlRequest: URLRequest) async -> UIImage? {
        do {
            let result = try await imageLoader.fetch(urlRequest)
            return result
        } catch {
            print(error.localizedDescription)
            return nil
        }
    }
}

struct URLImage: View {
    private let viewModel: URLImageViewModel
    private let contentMode: ContentMode
    private let fallbackColor: Color
    
    @State private var image: UIImage?
    init(url: URL, contentMode: ContentMode = .fill, fallbackColor: Color = ColorName.background.color(variation: .secondary)) {
        self.init(request: URLRequest(url: url), contentMode: contentMode, fallbackColor: fallbackColor)
    }

    init(request: URLRequest, contentMode: ContentMode = .fill, fallbackColor: Color = ColorName.background.color(variation: .secondary)) {
        self.viewModel = URLImageViewModel(urlRequest: request)
        self.contentMode = contentMode
        self.fallbackColor = fallbackColor
    }

    var body: some View {
        GeometryReader { geoProxy in
            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .aspectRatio(contentMode: self.contentMode)
                    .frame(width: geoProxy.size.width, height: geoProxy.size.height, alignment: .center)
            } else {
                Rectangle()
                    .fill(fallbackColor)
                    .frame(width: geoProxy.size.width, height: geoProxy.size.height, alignment: .center)
            }
        }
        .onReceive(viewModel.$image) { imageMaybe in
            withAnimation {
                image = imageMaybe
            }
        }
    }
}
