import Combine
import Photos
import PhotosUI
import SwiftUI
import UIKit

struct RecentPhotoItem: Identifiable, Equatable {
    let id: String
    let asset: PHAsset
    let thumbnail: UIImage
}

@MainActor
final class PhotoLibraryService: NSObject, ObservableObject {
    @Published private(set) var authorizationStatus: PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
    @Published private(set) var recentPhotos: [RecentPhotoItem] = []
    @Published private(set) var isLoading = false

    private let imageManager = PHCachingImageManager()

    var canBrowseRecents: Bool {
        authorizationStatus == .authorized || authorizationStatus == .limited
    }

    var statusMessage: String {
        switch authorizationStatus {
        case .authorized:
            return "Recent photos"
        case .limited:
            return "Limited photo access"
        case .denied:
            return "Photo access denied"
        case .restricted:
            return "Photo access restricted"
        case .notDetermined:
            return "Show recent photos"
        @unknown default:
            return "Photo access unavailable"
        }
    }

    func requestAccessAndLoad() async {
        if authorizationStatus == .notDetermined {
            authorizationStatus = await PHPhotoLibrary.requestAuthorization(for: .readWrite)
        }
        await refreshRecentsIfPossible()
    }

    func refreshRecentsIfPossible() async {
        authorizationStatus = PHPhotoLibrary.authorizationStatus(for: .readWrite)
        guard canBrowseRecents else {
            recentPhotos = []
            return
        }

        isLoading = true
        defer { isLoading = false }

        let options = PHFetchOptions()
        options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
        options.fetchLimit = 12
        let assets = PHAsset.fetchAssets(with: .image, options: options)
        var results: [RecentPhotoItem] = []

        assets.enumerateObjects { asset, _, _ in
            results.append(contentsOf: self.thumbnailItem(for: asset).map { [$0] } ?? [])
        }

        recentPhotos = results
    }

    func loadImage(for item: RecentPhotoItem) async -> UIImage? {
        await withCheckedContinuation { continuation in
            let options = PHImageRequestOptions()
            options.deliveryMode = .highQualityFormat
            options.resizeMode = .fast
            options.isNetworkAccessAllowed = true

            imageManager.requestImageDataAndOrientation(for: item.asset, options: options) { data, _, _, _ in
                continuation.resume(returning: data.flatMap(UIImage.init(data:)))
            }
        }
    }

    func presentLimitedLibraryPicker() {
        guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
              let rootViewController = scene.keyWindow?.rootViewController else {
            return
        }

        PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: rootViewController)
    }

    func openSettings() {
        guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
        UIApplication.shared.open(url)
    }

    private func thumbnailItem(for asset: PHAsset) -> RecentPhotoItem? {
        let targetSize = CGSize(width: 180, height: 180)
        let options = PHImageRequestOptions()
        options.deliveryMode = .opportunistic
        options.resizeMode = .fast
        options.isSynchronous = true

        var thumbnailImage: UIImage?
        imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { image, _ in
            thumbnailImage = image
        }

        guard let thumbnailImage else { return nil }
        return RecentPhotoItem(id: asset.localIdentifier, asset: asset, thumbnail: thumbnailImage)
    }
}

private extension UIWindowScene {
    var keyWindow: UIWindow? {
        windows.first(where: \.isKeyWindow)
    }
}
