import SwiftUI
import FirebaseFirestore
import FirebaseAuth

class TrendingSongManager: ObservableObject {
    static let shared = TrendingSongManager()

    @Published var hooksFeed: [[UploadedSong]] = []
    @Published var songs: [UploadedSong] = []
    @Published var isLoading: Bool = false
    @Published var errorMessage: String?

    private let db = Firestore.firestore()
    private var listener: ListenerRegistration?

    private init() {
        fetchTrendingSongs()
    }

    func fetchTrendingSongs() {
        isLoading = true
        errorMessage = nil

        // Query Firestore for songs where isLikedByCreator == true
        listener = db.collection("song")
            .whereField("isLikedByCreator", isEqualTo: true)
            .order(by: "createdAt", descending: true) // Most recent first
            .addSnapshotListener { [weak self] querySnapshot, error in
                guard let self = self else { return }

                if let error = error {
                    self.isLoading = false
                    self.errorMessage = "Error fetching trending songs: \(error.localizedDescription)"
                    print("❌ Error fetching trending songs: \(error)")
                    return
                }

                guard let documents = querySnapshot?.documents else {
                    self.isLoading = false
                    self.errorMessage = "No trending songs found"
                    self.songs = []
                    return
                }

                // Fetch all songs with their artist info
                self.fetchSongsWithArtistInfo(documents: documents)
            }
    }

    private func fetchSongsWithArtistInfo(documents: [QueryDocumentSnapshot]) {
        // Create a dispatch group to wait for all artist fetches
        let dispatchGroup = DispatchGroup()
        var fetchedSongs: [UploadedSong] = []

        // Get current user ID to check if songs are created by them
        let currentUserId = Auth.auth().currentUser?.uid

        for document in documents {
            let data = document.data()
            guard let name = data["name"] as? String,
                  let createdByRef = data["createdBy"] as? DocumentReference,
                  let createdAt = (data["createdAt"] as? Timestamp)?.dateValue() else {
                continue
            }

            dispatchGroup.enter()

            // Fetch artist info
            createdByRef.getDocument { artistSnapshot, error in
                defer { dispatchGroup.leave() }

                if let error = error {
                    print("❌ Error fetching artist info: \(error)")
                    return
                }

                let artistName = (artistSnapshot?.data()?["displayName"] as? String) ?? "Unknown Artist"
                let isCreatedByCurrentUser = createdByRef.documentID == currentUserId

                let song = UploadedSong(
                    id: document.documentID,
                    name: name,
                    artistName: artistName,
                    artistId: createdByRef.documentID,
                    createdAt: createdAt,
                    imageURL: data["imageURL"] as? String,
                    audioURL: data["audioURL"] as? String,
                    originalPrompt: data["originalPrompt"] as? String,
                    rewrittenPrompt: data["rewrittenPrompt"] as? String,
                    status: data["status"] as? String,
                    rootRemixSongId: (data["rootRemixSong"] as? DocumentReference)?.documentID,
                    isCreatedByCurrentUser: isCreatedByCurrentUser,
                    isLikedByCreator: data["isLikedByCreator"] as? Bool ?? false,
                    hooksStartPoint: data["hooksStartPoint"] as? Double
                )

                fetchedSongs.append(song)
            }
        }

        dispatchGroup.notify(queue: .main) {
            self.fetchForHooksFeed(newSongs: fetchedSongs)
        }
    }

    func fetchForHooksFeed(newSongs: [UploadedSong]) {
        let group = DispatchGroup()

        guard !newSongs.isEmpty else {
            print("newSongs is empty")
            DispatchQueue.main.async {
                self.hooksFeed = []
            }
            return
        }

        var rootIDToUploadedSong: [String: UploadedSong] = [:]
        var rootIDToRemixes: [String: [UploadedSong]] = [:]
        for song in newSongs {
            guard let rootRemixSongId = song.rootRemixSongId else {
                print("missing rootRemixSongId")
                continue
            }

            let remixes = rootIDToRemixes[rootRemixSongId] ?? []
            rootIDToRemixes[rootRemixSongId] = remixes + [song]
//
//            guard rootIDToUploadedSong[rootRemixSongId] == nil else {
//                print("root song already fetched")
//                continue
//            }

            print("fetching rootSong \(rootRemixSongId)")
            group.enter()
            db.collection("song").document(rootRemixSongId).getDocument { rootRemixSnapshot, error in
                print("fetched rootSong \(rootRemixSongId)")
                defer { group.leave() }

                if let error = error {
                    print("Error fetching root remix song \(error)")
                    return
                }

                guard let rootRemixData = rootRemixSnapshot?.data(),
                      let name = rootRemixData["name"] as? String,
                      let createdByRef = rootRemixData["createdBy"] as? DocumentReference,
                      let createdAt = (rootRemixData["createdAt"] as? Timestamp)?.dateValue() else {
                    print("rootSong missing metadata \(rootRemixSnapshot?.data())")
                    return
                }
                
                print("fetching rootArtist \(createdByRef.documentID)")
                group.enter()
                createdByRef.getDocument { artistSnapshot, error in
                    print("fetched rootArtist \(createdByRef.documentID)")
                    defer { group.leave() }

                    if let error = error {
                        print("❌ Error fetching artist info: \(error)")
                        return
                    }

                    let artistName = (artistSnapshot?.data()?["displayName"] as? String) ?? "Unknown Artist"

                    let originalSong = UploadedSong(
                        id: rootRemixSongId,
                        name: name,
                        artistName: artistName,
                        artistId: createdByRef.documentID,
                        createdAt: createdAt,
                        imageURL: rootRemixData["imageURL"] as? String,
                        audioURL: rootRemixData["audioURL"] as? String,
                        originalPrompt: rootRemixData["originalPrompt"] as? String,
                        rewrittenPrompt: rootRemixData["rewrittenPrompt"] as? String,
                        status: rootRemixData["status"] as? String,
                        rootRemixSongId: (rootRemixData["rootRemixSong"] as? DocumentReference)?.documentID,
                        isCreatedByCurrentUser: false,
                        isLikedByCreator: false,
                        hooksStartPoint: rootRemixData["hooksStartPoint"] as? Double
                    )

                    rootIDToUploadedSong[rootRemixSongId] = originalSong
                }
            }
        }

        group.notify(queue: .global(qos: .userInitiated)) {
            var newFeed = [[UploadedSong]]()
            for (rootID, remixes) in rootIDToRemixes {
                print("root \(rootID) has \(remixes.count) remixes")
                guard let rootSong = rootIDToUploadedSong[rootID] else {
                    print("ERROR: Root song is missing from rootIDToUploadedSong")
                    continue
                }

                let feedItem = [rootSong] + remixes.sorted(by: { $0.createdAt > $1.createdAt })
                newFeed.append(feedItem)
            }

            newFeed.sort { firstFeedItem, secondFeedItem in
                let firstCreatedAt = firstFeedItem.count > 1 ? firstFeedItem[1].createdAt : firstFeedItem[0].createdAt
                let secondCreatedAt = secondFeedItem.count > 1 ? secondFeedItem[1].createdAt : secondFeedItem[0].createdAt

                return firstCreatedAt > secondCreatedAt
            }
            
            let sortedSongs = newSongs.sorted(by: { $0.createdAt > $1.createdAt })
            
            DispatchQueue.main.async {
                print("✅ Fetched \(newSongs.count) trending songs")
                print("✅ Fetched \(newFeed.count) hooks feed items")
                self.isLoading = false
                self.songs = sortedSongs
                self.hooksFeed = newFeed
            }
        }
    }

    func stopListening() {
        listener?.remove()
        listener = nil
    }

    deinit {
        stopListening()
    }
}
