import Foundation
import Combine
#if targetEnvironment(simulator)
#else
import FirebaseAuth
import FirebaseFirestore
#endif

private extension Post {
    static var userDefaultsKey = "bookmarks"
    static var hasSeenBookmarkTipKey = "hasSeenBookmarkTip"
}

extension UserDefaults {
    @objc dynamic var bookmarks: [String]? {
        stringArray(forKey: Post.userDefaultsKey)
    }
    
    @objc dynamic var hasSeenBookmarkTip: Bool {
        bool(forKey: Post.hasSeenBookmarkTipKey)
    }
}

protocol BookmarksRepository {
    func getBookmarks() async throws -> [String]
    @discardableResult func updateBookmarks(postIds: [String]) async throws -> Bool
    func didSeeBookmarksTip()
}

public class FirebaseBookmarksRepository: NSObject, BookmarksRepository {
    static let standard: FirebaseBookmarksRepository = {
        FirebaseBookmarksRepository()
    }()
 
    func didSeeBookmarksTip() {
        UserDefaults.standard.set( true, forKey: Post.hasSeenBookmarkTipKey)
    }
    
    func getBookmarks() async throws -> [String] {
#if targetEnvironment(simulator)
        UserDefaults.standard.bookmarks ?? []
#else
        return try await getDataFromFirebase()
#endif
    }
    
    private func getDataFromFirebase() async throws -> [String] {
#if targetEnvironment(simulator)
        throw(URLError.badServerResponse)
#else
        let firebaseAuthResponse = try await Auth.auth().signInAnonymously()
        let user = firebaseAuthResponse.user
        let db = Firestore.firestore()
        let documentRef = db.collection("users").document(user.uid)
        let snapshot = try await documentRef.getDocument()
        
        let data = snapshot.data()
        
        return data?["bookmarks"] as? [String] ?? []
        
#endif
    }
    
    @discardableResult
    func updateBookmarks(postIds: [String]) async throws -> Bool {
#if targetEnvironment(simulator)
        updateUserDefaults(postIds: postIds)
#else
        try await updateFirebase(postIds: postIds)
#endif
        return true
    }
    
    private func updateUserDefaults(postIds: [String]) {
        UserDefaults.standard.set( postIds.unique(), forKey: Post.userDefaultsKey)
    }
    
    private func updateFirebase(postIds: [String]) async throws {
        let dataDict = [Post.userDefaultsKey: postIds]
#if targetEnvironment(simulator)
        throw(URLError.badServerResponse)
#else
        let firebaseAuthResponse = try await Auth.auth().signInAnonymously()
        let user = firebaseAuthResponse.user
        let db = Firestore.firestore()
        let userDocumentRef = db.collection("users").document(user.uid)
        
        let _ = try await userDocumentRef.setData(dataDict, merge: true)
#endif
    }
}
