//
//  AttachmentViewModel+DragAndDrop.swift
//  
//
//  Created by MainasuK on 2022/11/8.
//

import UIKit
import Combine
import UniformTypeIdentifiers

// MARK: - TypeIdentifiedItemProvider
extension AttachmentViewModel: TypeIdentifiedItemProvider {
    public static var typeIdentifier: String {
        // must in UTI format
        // https://developer.apple.com/library/archive/qa/qa1796/_index.html
        return "org.joinmastodon.app.AttachmentViewModel"
    }
}

// MARK: - NSItemProviderWriting
extension AttachmentViewModel: NSItemProviderWriting {
    
    
    /// Attachment uniform type idendifiers
    ///
    /// The latest one for in-app drag and drop.
    /// And use generic `image` and `movie` type to
    /// allows transformable media in different formats
    public static var writableTypeIdentifiersForItemProvider: [String] {
        return [
            UTType.image.identifier,
            UTType.movie.identifier,
            AttachmentViewModel.typeIdentifier,
        ]
    }
    
    public var writableTypeIdentifiersForItemProvider: [String] {
        // should append elements in priority order from high to low
        var typeIdentifiers: [String] = []
        
        // FIXME: check jpg or png
        switch input {
        case .image:
            typeIdentifiers.append(UTType.png.identifier)
        case .url(let url), .mastodonAssetUrl(let url, _):
            let _uti = UTType(filenameExtension: url.pathExtension)
            if let uti = _uti {
                if uti.conforms(to: .image) {
                    typeIdentifiers.append(UTType.png.identifier)
                } else if uti.conforms(to: .movie) {
                    typeIdentifiers.append(UTType.mpeg4Movie.identifier)
                }
            }
        case .pickerResult(let item):
            if item.itemProvider.isImage() {
                typeIdentifiers.append(UTType.png.identifier)
            } else if item.itemProvider.isMovie() {
                typeIdentifiers.append(UTType.mpeg4Movie.identifier)
            }
        case .itemProvider(let itemProvider):
            if itemProvider.isImage() {
                typeIdentifiers.append(UTType.png.identifier)
            } else if itemProvider.isMovie() {
                typeIdentifiers.append(UTType.mpeg4Movie.identifier)
            }
        }
        
        typeIdentifiers.append(AttachmentViewModel.typeIdentifier)
        
        return typeIdentifiers
    }
    
    public func loadData(
        withTypeIdentifier typeIdentifier: String,
        forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void
    ) -> Progress? {
        switch typeIdentifier {
        case AttachmentViewModel.typeIdentifier:
            do {
                let archiver = NSKeyedArchiver(requiringSecureCoding: false)
                try archiver.encodeEncodable(id, forKey: NSKeyedArchiveRootObjectKey)
                archiver.finishEncoding()
                let data = archiver.encodedData
                completionHandler(data, nil)
            } catch {
                assertionFailure()
                completionHandler(nil, nil)
            }
        default:
            break
        }
        
        let loadingProgress = Progress(totalUnitCount: 100)
        
        Publishers.CombineLatest(
            $output,
            $error
        )
        .sink { [weak self] output, error in
            guard let self = self else { return }
            
            // continue when load completed
            guard output != nil || error != nil else { return }
            
            switch output {
            case .image(let data, _):
                switch typeIdentifier {
                case UTType.png.identifier:
                    loadingProgress.completedUnitCount = 100
                    completionHandler(data, nil)
                default:
                    completionHandler(nil, nil)
                }
            case .video(let url, _):
                switch typeIdentifier {
                case UTType.png.identifier:
                    let _image = AttachmentViewModel.createThumbnailForVideo(url: url)
                    let _data = _image?.pngData()
                    loadingProgress.completedUnitCount = 100
                    completionHandler(_data, nil)
                case UTType.mpeg4Movie.identifier:
                    let task = URLSession.shared.dataTask(with: url) { data, response, error in
                        completionHandler(data, error)
                    }
                    task.progress.observe(\.fractionCompleted) { progress, change in
                        loadingProgress.completedUnitCount = Int64(100 * progress.fractionCompleted)
                    }
                    .store(in: &self.observations)
                    task.resume()
                default:
                    completionHandler(nil, nil)
                }
            case nil:
                completionHandler(nil, error)
            }
        }
        .store(in: &disposeBag)
        
        return loadingProgress
    }
    
}
