//
//  PlaybarView.swift
//  Suno
//
//  Created by Martin Camacho on 1/7/24.
//

import Foundation
import AVFoundation
import SwiftUI
import Combine


import MediaPlayer

func setupNowPlayingInfo(title: String, artist: String, artworkURL: URL?) {
    var nowPlayingInfo = [String: Any]()
    nowPlayingInfo[MPMediaItemPropertyTitle] = title
    nowPlayingInfo[MPMediaItemPropertyArtist] = artist
    nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1.0
    nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = 0
    nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = 1.0
    nowPlayingInfo[MPNowPlayingInfoPropertyDefaultPlaybackRate] = 1.0
//    nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = 30
    
    if let artworkURL = artworkURL {
        // Use URLSession to download the artwork asynchronously
        let task = URLSession.shared.dataTask(with: artworkURL) { (data, response, error) in
            if let data = data, let artworkImage = UIImage(data: data) {
                DispatchQueue.main.async {
                    nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: artworkImage.size) { size in
                        return artworkImage
                    }
                    // Update nowPlayingInfo on the main thread
                    MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
                    
                    if let nowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo {
                        print("Updated now playing info:", nowPlayingInfo)
                    } else {
                        print("No now playing info available.")
                    }
                }
            } else {
                print("Error downloading artwork:", error?.localizedDescription ?? "Unknown error")
            }
        }
        task.resume()
    } else {
        // If artworkURL is nil, set nowPlayingInfo without artwork
        MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
        
        print("Updated now playing info:", nowPlayingInfo)
    }
}

func setupAudioSession() {
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(.playback)
        try audioSession.setActive(true)
        print("Set up audio session.")
    } catch {
        print("Error setting up audio session: \(error.localizedDescription)")
    }
}

class PlayerViewModel: ObservableObject {
    let player: AVPlayer = AVPlayer()
    @Published var currentClip: Clip?
    @Published var isPlaying: Bool = false
    
    private var playerStatusObserver: AnyCancellable?
    private var playerItemStatusObserver: AnyCancellable?

    
    init() {
        self.setupRemoteControlCenter()
        observePlayerStatus()
    }
    
    private func observePlayerStatus() {
        // Observing the player's timeControlStatus to update isPlaying
        playerStatusObserver = player.publisher(for: \.timeControlStatus)
            .receive(on: DispatchQueue.main)
            .map { $0 == .playing }
            .assign(to: \.isPlaying, on: self)
        
        // Optional: Observe the player item's status if needed, for example to detect when the player is ready to play
        playerItemStatusObserver = player.publisher(for: \.currentItem?.status)
            .receive(on: DispatchQueue.main)
            .sink { [weak self] status in
                switch status {
                case .readyToPlay:
                    // Handle ready to play if needed
                    break
                default:
                    break
                }
            }
    }
    
    private func setupRemoteControlCenter() {
        let commandCenter = MPRemoteCommandCenter.shared()
        
        commandCenter.playCommand.addTarget { event in
            self.player.play()
            return .success
        }
        
        commandCenter.pauseCommand.addTarget { event in
            self.player.pause()
            return .success
        }
    }

    
    func playClip(clip: Clip) {
        guard let audioUrlStr = clip.audioUrl, let url = URL(string: audioUrlStr) else {
            print("Invalid URL")
            return
        }
        
        if (clip.id == currentClip?.id) {
            if player.rate > 0 {
                player.pause()
            } else {
                player.play()
            }
        } else {
            currentClip = clip
            let playerItem = AVPlayerItem(url: url)
            player.replaceCurrentItem(with: playerItem)
            player.play()
            
            if let imageUrlString = clip.imageUrl,
               let imageUrl = URL(string: imageUrlString) {
                setupNowPlayingInfo(title: clip.title ?? "Untitled", artist: "Suno", artworkURL: imageUrl)
            } else {
                setupNowPlayingInfo(title: clip.title ?? "Untitled", artist: "Suno", artworkURL: nil)
            }
            
        }
    }
    
    func togglePlay() {
        if isPlaying {
            player.pause()
        } else {
            // If there's no clip loaded, you might want to handle this case differently.
            // For now, we'll just attempt to play if anything is loaded.
            if let currentClip = currentClip {
                player.play()
            } else {
                // This branch handles the case where togglePlay is called
                // without a current clip. You might want to ensure that
                // this scenario is either avoided or handled according to your app's logic.
                // For example, loading a default clip, showing an error, etc.
                print("No clip is currently loaded.")
            }
        }
    }
}


struct PlaybarView: View {
    @ObservedObject var playerViewModel: PlayerViewModel
    @State private var isModalPresented = false
    
    @State private var verticalPosition = 0.0
    
    
    var body: some View {
        if let clip = playerViewModel.currentClip {
            Button(action: {
                // Action to control playback
                isModalPresented = true
                
            }) {
                HStack {
                    // Add components of your playbar here
                    // For example: play/pause button, current track info, etc.
                    if let urlString = clip.imageUrl, let imageUrl = URL(string: urlString) {
                        AsyncImage(url: imageUrl) { image in
                            image.resizable()
                        } placeholder: {
                            ProgressView() // Show a progress indicator while loading
                        }
                        .frame(width: 40, height: 40)
                        .aspectRatio(contentMode: .fill)
                        .clipped()
                        .cornerRadius(10)
                    }
                    
                    VStack(alignment: .leading)  {
                        Text(clip.title ?? "Untitled")
                            .foregroundStyle(Color.white)
                        Text(clip.metadata.tags ?? "no style")
                            .foregroundStyle(Color.gray)
                    }
                    
                    Spacer()
                    
                    Button(action: {
                        // Your play/pause toggle action here
                        // This will typically involve toggling the isPlaying state
                        // and calling the appropriate methods to play or pause the audio
                        playerViewModel.togglePlay()
//                        self.isPlaying.toggle() // Assuming `isPlaying` is a state variable you have access to
                    }) {
                        Image(systemName: playerViewModel.isPlaying ? "pause.fill" : "play.fill")
                            .foregroundColor(.white)
                            .padding()
                            .background(Color.blue)
                            .clipShape(Circle())
                    }
                    
                    
                }
                
                // Add more components as needed
                .padding(10)
                .background(.thinMaterial) // Example background color
                .fullScreenCover(isPresented: $isModalPresented) {
                    // Your modal view content
                    // You can create a separate SwiftUI view or a custom view here
                    SongView(clip: clip)
                        .offset(y: verticalPosition)
                        .gesture(
                            gestureVertical()
                        )
                        .transition(.slide)
                }
            }
        } else {
            EmptyView()
        }
    }
    
    func gestureVertical() -> some Gesture {
        return DragGesture()
            .onChanged { value in
                if value.translation.height < 0 {
                    verticalPosition = 0
                } else {
                    verticalPosition = value.translation.height
                }
                
            }
            .onEnded { value in
                withAnimation(.linear(duration: 0.05)) {
                    isModalPresented.toggle()
                    verticalPosition = .zero
                }
            }
    }
}

struct PlaybarView_Previews: PreviewProvider {
    static var previews: some View {
        let clip = Clip(
            id: UUID(uuidString: "76D08F0A-6FB1-41E2-B0CB-12741AA2CCAB") ?? UUID(),
            audioUrl: "https://cdn1.suno.ai/76d08f0a-6fb1-41e2-b0cb-12741aa2ccab.mp3",
            title: "Celestial Dreams",
            imageUrl: "https://cdn1.suno.ai/image_76d08f0a-6fb1-41e2-b0cb-12741aa2ccab.png",
            metadata: ClipMetadata(
                tags: "pop",
                prompt: "[Verse]\nIn the darkness of the night, I look up to the sky\nMysterious lights shining bright, catching my eye (ooh)\nGazing at the moon, wishing upon a star\nLost in the wonders, wondering how far (ooh-yeah)\n\n[Chorus]\nCelestial dreams, taking me away (away)\nTo a world unknown, where fantasies play (play)\nFloating through galaxies, weightless and free\nIn celestial dreams, where I wanna be (ooh, yeah, yeah)"
            )
        )
        
        let playerViewModel = PlayerViewModel()
        playerViewModel.currentClip = clip
        
        return PlaybarView(playerViewModel: playerViewModel)
            .previewLayout(.sizeThatFits)
    }
}
