import SwiftUI

struct DownloadButton: View {
    private var model: Model

    @State private var status: String

    @State private var downloadTask: URLSessionDownloadTask?
    @State private var progress = 0.0
    @State private var observation: NSKeyValueObservation?

    private var onLoad: ((_ model: Model) -> Void)?

    init(model: Model) {
        self.model = model
        status = model.fileExists() ? "downloaded" : "download"
    }

    func onLoad(perform action: @escaping (_ model: Model) -> Void) -> DownloadButton {
        var button = self
        button.onLoad = action
        return button
    }

    private func download() {
        status = "downloading"
        print("Downloading model \(model.name) from \(model.url)")
        guard let url = URL(string: model.url) else { return }

        downloadTask = URLSession.shared.downloadTask(with: url) { temporaryURL, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            guard let response = response as? HTTPURLResponse, (200...299).contains(response.statusCode) else {
                print("Server error!")
                return
            }

            do {
                if let temporaryURL = temporaryURL {
                    try FileManager.default.copyItem(at: temporaryURL, to: model.fileURL)
                    print("Writing to \(model.filename) completed")
                    status = "downloaded"
                }
            } catch let err {
                print("Error: \(err.localizedDescription)")
            }
        }

        observation = downloadTask?.progress.observe(\.fractionCompleted) { progress, _ in
            self.progress = progress.fractionCompleted
        }

        downloadTask?.resume()
    }

    var body: some View {
        VStack {
            Button(action: {
                if (status == "download") {
                    download()
                } else if (status == "downloading") {
                    downloadTask?.cancel()
                    status = "download"
                } else if (status == "downloaded") {
                    if !model.fileExists() {
                        download()
                    }
                    onLoad?(model)
                }
            }) {
                let title = "\(model.name) \(model.info)"
                if (status == "download") {
                    Text("Download \(title)")
                } else if (status == "downloading") {
                    Text("\(title) (Downloading \(Int(progress * 100))%)")
                } else if (status == "downloaded") {
                    Text("Load \(title)")
                } else {
                    Text("Unknown status")
                }
            }.swipeActions {
                if (status == "downloaded") {
                    Button("Delete") {
                        do {
                            try FileManager.default.removeItem(at: model.fileURL)
                        } catch {
                            print("Error deleting file: \(error)")
                        }
                        status = "download"
                    }
                    .tint(.red)
                }
            }
        }
        .onDisappear() {
            downloadTask?.cancel()
        }
    }
}