import SwiftUI
import Combine

struct ChatView: View {
    @Environment(\.dismiss) private var dismiss
    @Binding var navigationPath: NavigationPath
    @State private var chatText: String = ""
    @StateObject private var chatService = GeminiChatService.shared
    @StateObject private var creditsManager = CreditsManager.shared
    @State private var messages: [ChatMessage] = []
    @State private var isLoading: Bool = false
    @State private var streamingResponse: String = ""
    @State private var currentSuggestions: [String] = []
    @State private var latestSongResponse: SongResponse? = nil
    @State private var currentLyrics: LyricsStructure? = nil
    @State private var chatTitle: String? = nil
    @State private var badgeCount: Int = 0
    @State private var currentlyPlayingSongId: String? = nil
    @State private var currentlySelectedSongId: String? = nil
    @StateObject private var audioManager = AudioManager.shared
    @State private var isCreatingMore: Bool = false
    @State private var lyricsText: String = ""
    @State private var showGenreSuggestions: Bool = false
    @State private var selectedGenres: [String] = []
    @State private var creativeGenreSuggestions: [String] = []
    @State private var showExtendSheet: Bool = false
    @State private var showReplaceSheet: Bool = false
    @State private var isLoadingGenres: Bool = false
    @State private var shouldScrollToBeginning = false
    @State private var shouldAutoScrollToBottom = false
    @State private var keyboardHeight: CGFloat = 0
    @State private var showUpsellAlert: Bool = false
    @State private var showChatSheet: Bool = true
    @State private var isChatBarFocused: Bool = false
    @State private var wasKeyboardVisible: Bool = false
    @State private var currentDetent: PresentationDetent = .height(120) // Will be updated in onAppear
    @State private var isEditingLyrics: Bool = false
    @State private var lyricsForEditing: String = ""
    @State private var styleForEditing: String = ""
    @State private var isNavigatingToWorkspace: Bool = false
    @State private var isInLyricsFocusMode: Bool = false
    @State private var isInExtendMode: Bool = false
    @State private var extensionTime: String = "0:30s"
    @State private var extendModelVersion: String = "v4.5"
    @State private var selectedModelVersion: String = "v5"
    @State private var audioFileName: String? = nil
    @State private var uploadProgress: Double = 0.0
    @State private var isUploading: Bool = false
    @State private var uploadCompleted: Bool = false
    @State private var currentWorkspaceId: String? = nil
    @StateObject private var workspaceManager = WorkspaceManager.shared
    @State private var showOnlySongs: Bool = false
    @State private var showWorkspacesMenu: Bool = false
    @State private var showRecordingSheet: Bool = false
    @State private var dynamicTextInputHeight: CGFloat = 56 // Track text input height dynamically
    @State private var customSheetDetent: CustomSheetDetent = .flex
    @State private var chatSheetHeight: CGFloat = 0 // Track actual chat sheet height

    // Create form state variables
    @State private var lyricsDescription: String = ""
    @State private var styleDescription: String = ""
    @State private var selectedModel: String = "v4.5"

    // Advanced options state
    @State private var weirdnessValue: Double = 0.5
    @State private var styleInfluenceValue: Double = 0.5
    @State private var audioInfluenceValue: Double = 0.5
    @State private var vocalGender: String = "Female"

    let onDismiss: () -> Void

    init(navigationPath: Binding<NavigationPath>, onDismiss: @escaping () -> Void = {}) {
        self._navigationPath = navigationPath
        self.onDismiss = onDismiss
    }
    
    // Fallback genre suggestions if API fails
    private let fallbackGenres = [
        "+pop", "+rock", "+hip-hop", "+r&b", "+indie", "+electronic", "+country", "+jazz",
        "+blues", "+folk", "+reggae", "+metal", "+punk", "+funk", "+disco", "+house",
        "+techno", "+drum & bass", "+dubstep", "+ambient", "+classical", "+latin",
        "+afrobeat", "+k-pop", "+reggaeton", "+trap", "+lo-fi", "+synthwave"
    ]
    
    private var isEmptyState: Bool {
        messages.isEmpty
    }
    
    // Dynamic genre suggestions based on what's already selected
    private var currentGenreSuggestions: [String] {
        let suggestions = !creativeGenreSuggestions.isEmpty ? creativeGenreSuggestions : fallbackGenres
        return Array(suggestions.filter { !selectedGenres.contains($0) }.prefix(8))
    }
    
    var body: some View {
        ZStack {
            NavigationStack {
                ZStack {
                VStack(spacing: 0) {
                    // Chat content container with overlay
                    ZStack {
                // Chat content (z-index 1)
                if isEmptyState {
                    // Empty chat content
                    EmptyChat(isAuraVisible: messages.isEmpty && !isLoading)
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                } else {
                    // Chat messages - always keep this view alive to preserve animation state
                    ChatsView(
                        messages: displayMessages,
                        currentlyPlayingSongId: currentlyPlayingSongId,
                        currentlySelectedSongId: currentlySelectedSongId,
                        isLoading: shouldShowLoadingMessage,
                        onSongPlayPause: handleSongPlayPause,
                        onSongSelect: handleSongSelection,
                        onCreateMore: handleCreateMore,
                        onLyricsExpand: handleLyricsExpand,
                        onLinkTap: handleLinkTap,
                        shouldAutoScroll: shouldAutoScrollToBottom,
                        audioManager: audioManager
                    )
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .opacity(showOnlySongs ? 0 : 1)

                    // Song grid view when playlist filter is active - overlay on top
                    if showOnlySongs {
                        songsGridView
                            .frame(maxWidth: .infinity, maxHeight: .infinity)
                    }
                }
            }


                }
                .background(Constants.Colors.Background.primary)

                // Slide-out workspaces menu overlay
                Color.black.opacity(showWorkspacesMenu ? 0.4 : 0)
                    .ignoresSafeArea()
                    .allowsHitTesting(showWorkspacesMenu)
                    .onTapGesture {
                        withAnimation(.easeInOut(duration: 0.3)) {
                            showWorkspacesMenu = false
                        }
                        showChatSheet = true // Show chat sheet again
                    }

                HStack(spacing: 0) {
                    WorkspacesView(
                        onBackTap: {
                            withAnimation(.easeInOut(duration: 0.3)) {
                                showWorkspacesMenu = false
                            }
                            showChatSheet = true // Show chat sheet again
                        },
                        onUploadTap: {
                            print("Upload tapped")
                        },
                        onSearchTap: {
                            print("Search tapped")
                        },
                        onNewWorkspaceTap: {
                            // Close the workspaces menu
                            withAnimation(.easeInOut(duration: 0.3)) {
                                showWorkspacesMenu = false
                            }
                            // Start a new chat (clear all messages and state)
                            startNewChat()
                            // Show the chat sheet
                            showChatSheet = true
                        },
                        onWorkspaceTap: { workspace in
                            // Do nothing for now
                        },
                        onWorkspaceMenuTap: { workspace in
                            print("Menu tapped for: \(workspace.name)")
                        }
                    )
                    .frame(width: UIScreen.main.bounds.width * 0.8)
                    .background(Constants.Colors.Background.primary)
                    .offset(x: showWorkspacesMenu ? 0 : -UIScreen.main.bounds.width * 0.8)

                    Spacer()
                }
                .ignoresSafeArea()
                .allowsHitTesting(showWorkspacesMenu)
            }
        .toolbarBackground(.hidden, for: .navigationBar)
        .toolbar {
            // Hide toolbar when workspaces menu is showing
            if !showWorkspacesMenu {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button {
                        // Show slide-out workspaces menu
                        withAnimation(.easeInOut(duration: 0.3)) {
                            showWorkspacesMenu = true
                        }
                        showChatSheet = false // Hide chat sheet
                        badgeCount = 0 // Reset badge
                    } label: {
                        Image("Icon/workspace")
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(width: 24, height: 24)
                    }
                }

                ToolbarItem(placement: .title) {
                    if isEmptyState {
                        // Just show text without menu when chat is empty
                        Text(chatTitle ?? "Chat")
                            .font(Constants.Typography.mediumTitle)
                            .foregroundColor(Constants.Colors.Foreground.primary)
                    } else {
                        // Show menu when chat has content
                        Menu {
                            // Share option
                            Button(action: {
                                print("Share tapped")
                            }) {
                                Label("Share", systemImage: "square.and.arrow.up")
                            }

                            Divider()

                            // Filter section
                            Section(header: Text("FILTER")) {
                                Button(action: {
                                    withAnimation(.easeInOut(duration: 0.2)) {
                                        showOnlySongs = false
                                    }
                                    // Show chat sheet when viewing all
                                    var transaction = Transaction()
                                    transaction.disablesAnimations = true
                                    withTransaction(transaction) {
                                        showChatSheet = true
                                    }
                                }) {
                                    Label("All", systemImage: !showOnlySongs ? "checkmark" : "")
                                }

                                Button(action: {
                                    withAnimation(.easeInOut(duration: 0.2)) {
                                        showOnlySongs = true
                                    }
                                    // Dismiss keyboard when showing only songs, but keep chat sheet visible
                                    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
                                }) {
                                    Label("Songs only", systemImage: showOnlySongs ? "checkmark" : "")
                                }
                            }

                            Divider()
                        } label: {
                            HStack(spacing: 4) {
                                Text(chatTitle ?? "Chat")
                                    .font(Constants.Typography.mediumTitle)
                                    .foregroundColor(Constants.Colors.Foreground.primary)

                                Image("Icon/triangle-down")
                                    .resizable()
                                    .frame(width: 16, height: 16)
                                    .foregroundColor(Constants.Colors.Foreground.primary)
                            }
                        }
                    }
                }

                ToolbarItem(placement: .subtitle) {
                    CreditsDisplay(selectedModel: selectedModel)
                }

                ToolbarItem(placement: .navigationBarTrailing) {
                    Button {
                        onDismiss()
                    } label: {
                        Image("Icon/chevron-down")
                            .resizable()
                            .frame(width: 24, height: 24)
                            .foregroundColor(Constants.Colors.Foreground.primary)
                    }
                }
            }
        }
        .onTapGesture {
            print("👆 Tap gesture triggered - isChatBarFocused: \(isChatBarFocused)")
            // Track if keyboard was visible before dismissing
            if isChatBarFocused {
                print("👆 User tapped outside - keyboard was focused, setting wasKeyboardVisible = true")
                wasKeyboardVisible = true
                isChatBarFocused = false
            } else {
                print("👆 User tapped but keyboard wasn't focused")
            }
            UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { notification in
            handleKeyboardWillShow(notification: notification)
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
            handleKeyboardWillHide()
        }
        .onAppear {
            // Initialize currentDetent to custom height
            customSheetDetent = .flex
            
            // Test API connection on startup
            Task {
                await chatService.testConnection()
            }
        }
        .onChange(of: navigationPath) { oldPath, newPath in
            print("🧭 Navigation path changed - isNavigatingToWorkspace: \(isNavigatingToWorkspace)")
            
            // If returning from workspaces (path got shorter and we were navigating to workspace)
            if isNavigatingToWorkspace && newPath.count < oldPath.count {
                print("🔄 Returning from workspaces - showing chat sheet")
                showChatSheet = true
                customSheetDetent = .flex
                isNavigatingToWorkspace = false
            }
        }
        .onReceive(audioManager.$currentlyPlayingSongId) { playingSongId in
            // Sync the ChatView state with AudioManager state
            currentlyPlayingSongId = playingSongId
        }
        .onReceive(audioManager.$isCurrentlyPlaying) { isPlaying in
            // Update playing state - if not playing, show as paused
            if !isPlaying && currentlyPlayingSongId != nil {
                // Song is paused, not stopped - keep the currentlyPlayingSongId for UI state
                print("🔄 Audio paused, keeping currentlyPlayingSongId for UI")
            }
        }
        .onAppear {
            print("🧭 ChatView appeared - showChatSheet: \(showChatSheet)")
        }
        .sheet(isPresented: $showExtendSheet) {
            ExtendView(
                songTitle: getCurrentSongTitle(),
                artworkGradient: getArtworkGradient(),
                isPlaying: currentlyPlayingSongId != nil,
                totalDuration: 180.0, // TODO: Get from actual song duration
                onPlayPause: {
                    // Handle play/pause for extend view
                    if let songResponse = latestSongResponse,
                       let song = songResponse.songs.first {
                        if currentlyPlayingSongId == song.id {
                            currentlyPlayingSongId = nil
                        } else {
                            currentlyPlayingSongId = song.id
                        }
                    }
                },
                onDone: { extensionTime in
                    // Close sheet first
                    showExtendSheet = false
                    
                    // Send extension request message
                    let songTitle = getCurrentSongTitle()
                    let message = "Extend \(songTitle) after \(extensionTime)"
                    
                    // Set extension-specific suggestions
                    currentSuggestions = ["3rd verse", "Bridge", "Funky solo instrumental", "Drum break", "Vocal ad libs break"]
                    
                    // Set chat text and send message
                    chatText = message
                    sendMessage()
                },
                onDismiss: {
                    showExtendSheet = false
                }
            )
            .presentationDetents([.medium])
            .presentationDragIndicator(.visible)
            .presentationCornerRadius(38)
        }
        .sheet(isPresented: $showReplaceSheet) {
            ReplaceView(
                songTitle: getCurrentSongTitle(),
                artworkGradient: getArtworkGradient(),
                isPlaying: currentlyPlayingSongId != nil,
                totalDuration: 180.0, // TODO: Get from actual song duration
                onPlayPause: {
                    // Handle play/pause for replace view
                    if let songResponse = latestSongResponse,
                       let song = songResponse.songs.first {
                        if currentlyPlayingSongId == song.id {
                            currentlyPlayingSongId = nil
                        } else {
                            currentlyPlayingSongId = song.id
                        }
                    }
                },
                onDone: { startTime, endTime in
                    // Close sheet first
                    showReplaceSheet = false
                    
                    // Send replace request message
                    let songTitle = getCurrentSongTitle()
                    let message = "Ok got it, I'll replace \(songTitle) from \(startTime) - \(endTime). Before I proceed, let me know if you want to add lyrics or the vibe of your instrumental"
                    
                    // Set replace-specific suggestions
                    currentSuggestions = ["Add lyrics", "Instrumental vibe", "More upbeat", "Slower tempo", "Different genre"]
                    
                    // Add the message as an incoming (AI) message
                    let incomingMessage = ChatMessage(content: message, isOutgoing: false)
                    messages.append(incomingMessage)
                },
                onDismiss: {
                    showReplaceSheet = false
                }
            )
            .presentationDetents([.medium])
            .presentationDragIndicator(.visible)
            .presentationCornerRadius(38)
        }
        .alert("Upsell page", isPresented: $showUpsellAlert) {
            Button("OK") {
                // Alert automatically dismisses
            }
        }
        .onChange(of: customSheetDetent) { oldDetent, newDetent in
            // Populate form when swiping up to full mode with a selected song
            if oldDetent == .flex && newDetent == .full {
                populateFormFromSelectedSong()
            }

            // Reset modes when sheet is swiped down to flex size
            if oldDetent == .full && newDetent == .flex {
                isInLyricsFocusMode = false
                isEditingLyrics = false
                resetExtendMode()
            }
        }
            }

            // CustomSheet overlays the entire view
            CustomSheet(
            isPresented: $showChatSheet,
            currentDetent: $customSheetDetent,
            detents: [.flex, .full],
            style: .floating,
            background: .glass,
            sheetHeight: $chatSheetHeight
        ) {
                VStack(spacing: 0) {
                    // ChatBar always visible
                    createChatBar()
                }
        } aboveSheetContent: {
            // Presets scroller - appears above sheet in .flex mode only when empty
            if isEmptyState {
                PresetsScroller(
                    onPresetTap: { preset in
                        chatText = preset
                        sendMessage()
                    },
                    bottomPadding: 0
                )
            }

            // Suggestions - appears above sheet when there are suggestions
            if !isEmptyState && shouldShowSuggestions {
                suggestionsView
            }
        }
        .onDisappear {
                print("📱 Sheet disappeared - isChatBarFocused: \(isChatBarFocused), wasKeyboardVisible: \(wasKeyboardVisible), isNavigatingToWorkspace: \(isNavigatingToWorkspace), showOnlySongs: \(showOnlySongs)")

                // Auto-reopen if keyboard was dismissed by user tapping outside
                // BUT NOT if we're showing only songs or workspaces menu
                if (isChatBarFocused || wasKeyboardVisible) && !isNavigatingToWorkspace && !showOnlySongs && !showWorkspacesMenu {
                    print("🔄 Auto-reopening chat sheet after keyboard dismissal")
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                        showChatSheet = true
                        customSheetDetent = .flex
                        wasKeyboardVisible = false // Reset the flag
                    }
                } else {
                    print("❌ Not auto-reopening: condition failed")
                }

            }
        .sheet(isPresented: $showRecordingSheet, onDismiss: {
            // Re-show chat sheet after recording sheet is dismissed
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                showChatSheet = true
                customSheetDetent = .flex
            }
        }) {
            RecordingSheet(onDismiss: {
                showRecordingSheet = false
            })
            .presentationDetents([.medium])
            .presentationDragIndicator(.visible)
            .presentationCornerRadius(36)
        } // Closes .sheet trailing closure
        } // Closes outer ZStack
    } // Closes body

    private var displayMessages: [ChatMessage] {
        var allMessages = messages

        // Add streaming response if it exists
        if !streamingResponse.isEmpty {
            let streamingMessage = ChatMessage(
                content: streamingResponse,
                isOutgoing: false
            )
            allMessages.append(streamingMessage)
        }

        // Filter to only show messages with songs if showOnlySongs is enabled
        if showOnlySongs {
            return allMessages.filter { $0.songData != nil }
        }

        return allMessages
    }
    
    private var shouldShowLoadingMessage: Bool {
        return isLoading && streamingResponse.isEmpty
    }

    private var songsGridView: some View {
        ScrollView {
            LazyVGrid(columns: [
                GridItem(.flexible(), spacing: 16),
                GridItem(.flexible(), spacing: 16)
            ], spacing: 16) {
                ForEach(getAllGeneratedSongs(), id: \.id) { song in
                    InlineChatPlayer(
                        songTitle: song.title,
                        genres: song.genres,
                        isPlaying: currentlyPlayingSongId == song.id && (audioManager.isCurrentlyPlaying),
                        isSelected: currentlySelectedSongId == song.id,
                        progress: (currentlyPlayingSongId == song.id) ? audioManager.currentProgress : 0.0,
                        artworkGradient: createGradientForSong(song),
                        onPlayPause: {
                            handleSongPlayPause(songId: song.id)
                        },
                        onSelect: {
                            handleSongSelection(songId: song.id)
                        },
                        onExpand: {
                            print("Expand song: \(song.title)")
                        },
                        onProgressChanged: { progress in
                            if currentlyPlayingSongId == song.id {
                                audioManager.seekToProgress(progress)
                            }
                        },
                        onScrubStart: {
                            if currentlyPlayingSongId == song.id {
                                audioManager.startScrubbing()
                            }
                        },
                        onScrubEnd: {
                            if currentlyPlayingSongId == song.id {
                                audioManager.endScrubbing()
                            }
                        },
                        onThumbsUp: {
                            print("Thumbs up for: \(song.title)")
                        },
                        onThumbsDown: {
                            print("Thumbs down for: \(song.title)")
                        },
                        onShare: {
                            print("Share: \(song.title)")
                        },
                        onMore: {
                            print("More options for: \(song.title)")
                        }
                    )
                }
            }
            .padding(.vertical, 12)
            .padding(.horizontal, 16)
        }
    }

    private var shouldShowSuggestions: Bool {
        let displaySuggestions = showGenreSuggestions ? currentGenreSuggestions : (currentlySelectedSongId != nil ? currentSuggestions : [])
        return !displaySuggestions.isEmpty
    }

    private var displaySuggestions: [String] {
        showGenreSuggestions ? currentGenreSuggestions : (currentlySelectedSongId != nil ? currentSuggestions : [])
    }

    private var suggestionsView: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 8) {
                // Suggestion pills
                ForEach(Array(displaySuggestions.prefix(5).enumerated()), id: \.offset) { index, suggestion in
                    Button(action: {
                        handleSuggestionTap(suggestion)
                    }) {
                        Text(suggestion.uppercased())
                            .font(Constants.Typography.timecode)
                            .kerning(0.2)
                            .foregroundColor(Constants.Colors.Foreground.primary)
                            .lineLimit(1)
                            .padding(.horizontal, 12)
                            .padding(.vertical, 8)
                            .glassEffect(.regular.interactive(), in: RoundedRectangle(cornerRadius: 100))
                    }
                    .buttonStyle(PlainButtonStyle())
                }
            }
            .padding(.horizontal, 16)
            .padding(.vertical, 12)
        }
    }

    private func handleActionTap() {
        // Actions from EmptyChat - could add predefined messages here
        print("Action tapped from empty chat")
    }
    
    private func sendMessage() {
        guard !chatText.isEmpty && !isLoading else { return }
        
        // Check if this might be a song generation request and if user has enough credits
        if mightGenerateSong(chatText) && !creditsManager.hasEnoughCredits(50) {
            // Show insufficient credits message instead of processing
            let insufficientCreditsMessage = ChatMessage(
                content: "You don't have enough credits to generate songs. Come back tomorrow for more credits or upgrade to premium.",
                isOutgoing: false
            )
            messages.append(insufficientCreditsMessage)
            return
        }
        
        let userMessage = chatText
        let currentAudioFileName = audioFileName // Capture before resetting
        chatText = ""
        
        // Reset genre suggestions state when sending message
        showGenreSuggestions = false
        selectedGenres = []
        creativeGenreSuggestions = []
        shouldScrollToBeginning = false
        
        // Reset lyrics editing state when sending message
        isEditingLyrics = false
        lyricsForEditing = ""
        styleForEditing = ""
        isInLyricsFocusMode = false
        
        // Reset audio reference state after sending message
        audioFileName = nil
        uploadProgress = 0.0
        isUploading = false
        uploadCompleted = false
        
        // Dismiss keyboard when sending message
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
        
        // Set chat title if this is the first message
        if messages.isEmpty {
            Task {
                await generateChatTitle(from: userMessage)
            }
        }
        
        // Add user message immediately
        let outgoingMessage = ChatMessage(content: userMessage, isOutgoing: true, audioFileName: currentAudioFileName)
        messages.append(outgoingMessage)
        
        // Debug: Check if audio file was attached
        if let audioFile = currentAudioFileName {
            print("📎 Outgoing message created with audio file: \(audioFile)")
        }
        
        // Set loading state
        isLoading = true
        streamingResponse = ""
        
        // Send to Gemini
        Task {
            do {
                let response = try await chatService.sendMessage(userMessage, audioFileName: currentAudioFileName) { chunk in
                    DispatchQueue.main.async {
                        streamingResponse += chunk
                    }
                }
                
                DispatchQueue.main.async {
                    // Parse response to check if it contains song data
                    // Use the actual response, not streamingResponse (which is empty for mock data)
                    let responseToCheck = !streamingResponse.isEmpty ? streamingResponse : response
                    
                    if let songResponse = parseSongResponse(from: responseToCheck) {
                        // Handle song generation response
                        latestSongResponse = songResponse
                        currentSuggestions = songResponse.suggestions
                        
                        // Add generated songs to current workspace
                        if let workspaceId = currentWorkspaceId {
                            for song in songResponse.songs {
                                workspaceManager.addSongToWorkspace(workspaceId: workspaceId, song: song)
                            }
                        }
                        
                        // Store lyrics if they exist (for first-time generations)
                        if let lyrics = songResponse.lyrics {
                            currentLyrics = lyrics
                        }
                        
                        // Increment badge count by 2 for each song generation
                        badgeCount += 2
                        
                        // Create a song generation message instead of regular text
                        addSongGenerationMessage(songResponse)
                    } else {
                        // Regular text response
                        if !responseToCheck.isEmpty {
                            let incomingMessage = ChatMessage(content: responseToCheck, isOutgoing: false)
                            messages.append(incomingMessage)
                        }
                    }
                    
                    streamingResponse = ""
                    isLoading = false
                }
            } catch {
                DispatchQueue.main.async {
                    print("Error sending message: \(error)")
                    
                    // Add error message
                    let errorMessage = ChatMessage(content: "Sorry, I'm having trouble responding right now. Please try again.", isOutgoing: false)
                    messages.append(errorMessage)
                    
                    streamingResponse = ""
                    isLoading = false
                }
            }
        }
    }

    private func sendCreateMessage() {
        // Build formatted message from create form
        var messageParts: [String] = []

        messageParts.append("Create a song with:")

        // Lyrics
        if !lyricsDescription.isEmpty {
            messageParts.append("Lyrics: \(lyricsDescription)")
        }

        // Style
        if !styleDescription.isEmpty {
            messageParts.append("Style: \(styleDescription)")
        }

        // Advanced Options (only include if not default values)
        var advancedOptionsParts: [String] = []

        if weirdnessValue != 0.5 {
            advancedOptionsParts.append("Weirdness: \(Int(weirdnessValue * 100))%")
        }

        if styleInfluenceValue != 0.5 {
            advancedOptionsParts.append("Style Influence: \(Int(styleInfluenceValue * 100))%")
        }

        if audioInfluenceValue != 0.5 {
            advancedOptionsParts.append("Audio Influence: \(Int(audioInfluenceValue * 100))%")
        }

        if vocalGender != "Female" {
            advancedOptionsParts.append("Vocal Gender: \(vocalGender)")
        }

        if !advancedOptionsParts.isEmpty {
            messageParts.append("Advanced Options: \(advancedOptionsParts.joined(separator: ", "))")
        }

        // Model
        messageParts.append("Model: Suno \(selectedModel)")

        // Join all parts with newlines
        let formattedMessage = messageParts.joined(separator: "\n")

        // Set chatText to the formatted message
        chatText = formattedMessage

        // Change sheet detent back to .flex
        withAnimation(.easeInOut(duration: 0.3)) {
            customSheetDetent = .flex
        }

        // Send the message using existing sendMessage logic
        sendMessage()

        // Reset form fields after sending
        lyricsDescription = ""
        styleDescription = ""
        weirdnessValue = 0.5
        styleInfluenceValue = 0.5
        audioInfluenceValue = 0.5
        vocalGender = "Female"
    }

    private func handleSuggestionTap(_ suggestion: String) {
        // Check if this is a lyrics editor suggestion
        let lowercased = suggestion.lowercased()
        if lowercased.contains("edit lyrics") || lowercased.contains("lyrics editor") {
            // Expand chat sheet to large detent for lyrics editing
            // This will show CreateView with lyrics pre-populated and style collapsed
            if currentLyrics != nil {
                isEditingLyrics = true
                isInLyricsFocusMode = true
                customSheetDetent = .full
            }
            return
        }
        
        // Check if this is an extend suggestion
        if lowercased.contains("extend") {
            // Expand chat sheet to large and show CreateExtendPlayer
            isInExtendMode = true
            isEditingLyrics = false
            isInLyricsFocusMode = false
            customSheetDetent = .full
            return
        }
        
        // Check if this is a replace suggestion
        if lowercased.contains("replace") {
            // Open replace sheet directly without adding any messages
            showReplaceSheet = true
            return
        }
        
        // Check if this is a change genre suggestion
        if lowercased.contains("change genre") {
            // Show genre suggestions instead of sending message
            showGenreSuggestions = true
            selectedGenres = []
            
            // Auto-fill with specific song title and version number
            let currentSong = getCurrentSongTitle()
            chatText = "\(currentSong) - Change the genre to "
            
            // Load creative genre suggestions from Gemini
            loadCreativeGenreSuggestions()
            return
        }
        
        // Clear current suggestions only when sending a message
        currentSuggestions = []
        
        // Send the suggestion as a new message
        chatText = suggestion
        sendMessage()
    }
    
    private func handleGenreSuggestionTap(_ genre: String) {
        // Extract clean genre name (remove + prefix for storage and display)
        let cleanGenre = genre.hasPrefix("+") ? String(genre.dropFirst()) : genre
        
        // Add genre to selected genres (store without + prefix)
        selectedGenres.append(cleanGenre)
        
        // Extract song title prefix if it exists
        let currentSong = getCurrentSongTitle()
        let songPrefix = "\(currentSong) - "
        
        // Update chat text with selected genres, preserving song title prefix
        let genreList = selectedGenres.joined(separator: ", ")
        chatText = "\(songPrefix)Change the genre to \(genreList)"
        
        // Always reload creative suggestions with updated selected genres
        // User can select as many genres as they like
        loadCreativeGenreSuggestions()
    }
    
    private func parseSongResponse(from response: String) -> SongResponse? {
        // Try to parse JSON from the response
        print("🔍 Parsing response: \(response.prefix(200))...")
        
        guard let data = response.data(using: .utf8) else {
            print("❌ Failed to convert response to data")
            return nil
        }
        
        do {
            let songResponse = try JSONDecoder().decode(SongResponse.self, from: data)
            print("✅ Successfully parsed song response with \(songResponse.songs.count) songs")
            return songResponse
        } catch {
            print("❌ JSON parsing error: \(error)")
            return nil
        }
    }
    
    private func addSongGenerationMessage(_ songResponse: SongResponse) {
        // Deduct 50 credits for song generation
        creditsManager.deductCredits(50)
        
        // Check if this is a follow-up "create more" request
        let isCreateMoreResponse = isLastMessageCreateMore()
        
        // For "create more" responses, don't show the reply text - only songs
        let messageContent = isCreateMoreResponse ? "" : songResponse.reply
        
        // Create a message with song data
        let message = ChatMessage(
            content: messageContent,
            isOutgoing: false,
            songData: songResponse
        )
        messages.append(message)
        
        // Update workspace song count
        if let workspaceId = currentWorkspaceId {
            let totalSongs = getAllGeneratedSongs().count
            workspaceManager.updateWorkspaceSongCount(id: workspaceId, songCount: totalSongs)
            print("📁 Updated workspace song count to: \(totalSongs)")
        }
        
        // Auto-select the first song when a new song generation message is added
        if let firstSong = songResponse.songs.first {
            currentlySelectedSongId = firstSong.id
            print("🎯 Auto-selecting first song: \(firstSong.title) (id: \(firstSong.id))")
        }
    }
    
    private func isLastMessageCreateMore() -> Bool {
        return isCreatingMore
    }
    
    private func handleLyricsExpand() {
        // Mark that we're editing lyrics to change header title
        isEditingLyrics = true
        
        // Expand chat sheet to large detent to show CreateView
        // CreateView will automatically be populated with current song data
        customSheetDetent = .full
    }
    
    private func getCurrentSongTitle() -> String {
        // First priority: get the currently playing song title
        if let currentSong = getCurrentlyPlayingSong() {
            return currentSong.title
        }
        
        // Second priority: get the most recent song from the latest song response
        if let latestSong = latestSongResponse?.songs.first {
            return latestSong.title
        }
        
        // Fallback if no song is available
        return "Song (#1)"
    }
    
    private func getCurrentArtworkGradient() -> LinearGradient {
        // First priority: get the currently playing song's artwork gradient
        if let currentSong = getCurrentlyPlayingSong() {
            return createGradientForSong(currentSong)
        }
        
        // Second priority: get the most recent song's artwork gradient
        if let latestSong = latestSongResponse?.songs.first {
            return createGradientForSong(latestSong)
        }
        
        // Fallback to default gradient
        return getArtworkGradient()
    }
    
    private func getArtworkGradient() -> LinearGradient {
        // TODO: Generate or get artwork gradient based on song
        return LinearGradient(
            colors: [
                Color(red: 0.8, green: 0.4, blue: 0.9),
                Color(red: 0.4, green: 0.6, blue: 1.0)
            ],
            startPoint: .topLeading,
            endPoint: .bottomTrailing
        )
    }
    
    private func handleLinkTap(_ url: String) {
        if url == "lyrics-editor-link" {
            if let songResponse = latestSongResponse,
               let lyrics = songResponse.lyrics {
                let destination = MainDestination.lyricsEditor(lyrics: lyrics, songTitle: getCurrentSongTitle())
                navigationPath.append(destination)
            }
        } else if url == "premium-upgrade" {
            // Show upsell alert for premium upgrade
            showUpsellAlert = true
        }
    }
    
    private func generateChatTitle(from message: String) async {
        do {
            let titlePrompt = "Generate a simple 2-4 word title for a chat conversation based on this user request: '\(message)'. Only respond with the title, no quotes or extra text."
            
            let generatedTitle = try await chatService.sendSimpleTextMessage(titlePrompt)
            
            DispatchQueue.main.async {
                // Clean up the generated title - remove quotes, JSON formatting, etc.
                var cleanTitle = generatedTitle.trimmingCharacters(in: .whitespacesAndNewlines)
                cleanTitle = cleanTitle.replacingOccurrences(of: "\"", with: "")
                cleanTitle = cleanTitle.replacingOccurrences(of: "'", with: "")
                
                // If it still looks like JSON or contains unwanted characters, use fallback
                if cleanTitle.contains("{") || cleanTitle.contains("}") || cleanTitle.contains("[") || cleanTitle.contains("]") {
                    self.chatTitle = self.generateFallbackTitle(from: message)
                } else {
                    self.chatTitle = cleanTitle
                }
                
                // Create a new workspace with the chat title
                if let title = self.chatTitle, self.currentWorkspaceId == nil {
                    let workspace = self.workspaceManager.createWorkspace(title: title, songCount: 0)
                    self.currentWorkspaceId = workspace.id
                    print("📁 Created new workspace: \(title) (ID: \(workspace.id))")
                }
            }
        } catch {
            // Fallback to simple title generation if API fails
            DispatchQueue.main.async {
                self.chatTitle = self.generateFallbackTitle(from: message)
                
                // Create a new workspace with the fallback title
                if let title = self.chatTitle, self.currentWorkspaceId == nil {
                    let workspace = self.workspaceManager.createWorkspace(title: title, songCount: 0)
                    self.currentWorkspaceId = workspace.id
                    print("📁 Created new workspace (fallback): \(title) (ID: \(workspace.id))")
                }
            }
        }
    }
    
    private func generateFallbackTitle(from message: String) -> String {
        let lowercased = message.lowercased()
        
        // Simple keyword-based title generation
        if lowercased.contains("best friend") || lowercased.contains("friend") {
            return "Song about my best friend"
        } else if lowercased.contains("love") || lowercased.contains("relationship") {
            return "Love song"
        } else if lowercased.contains("sad") || lowercased.contains("heartbreak") {
            return "Sad song"
        } else if lowercased.contains("happy") || lowercased.contains("upbeat") {
            return "Happy song"
        } else if lowercased.contains("birthday") {
            return "Birthday song"
        } else if lowercased.contains("christmas") || lowercased.contains("holiday") {
            return "Holiday song"
        } else if lowercased.contains("summer") {
            return "Summer song"
        } else if lowercased.contains("dance") {
            return "Dance song"
        } else {
            // Fallback: take first few words and add "song"
            let words = message.components(separatedBy: .whitespacesAndNewlines).prefix(3)
            return "Song about " + words.joined(separator: " ").lowercased()
        }
    }
    
    private func getAllGeneratedSongs() -> [Song] {
        var allSongs: [Song] = []
        
        for message in messages {
            if let songData = message.songData {
                allSongs.append(contentsOf: songData.songs)
            }
        }
        
        return allSongs
    }
    
    private func findSongById(songId: String) -> Song? {
        // Search through all messages for the song with the matching ID
        for message in messages.reversed() {
            if let songData = message.songData {
                if let song = songData.songs.first(where: { $0.id == songId }) {
                    return song
                }
            }
        }
        return nil
    }
    
    private func handleSongPlayPause(songId: String) {
        print("🔥 handleSongPlayPause called with songId: \(songId)")
        
        // Find the song to get its audioURL
        let song = findSongById(songId: songId)
        
        // Debug logging
        print("🔍 Found song: \(song?.title ?? "nil")")
        print("🔍 Song audioURL: \(song?.audioURL ?? "nil")")
        
        // If this is a different song than currently playing, stop the current one first
        if let currentSongId = audioManager.currentlyPlayingSongId, currentSongId != songId {
            print("🛑 Stopping current song (\(currentSongId)) to play new song")
            audioManager.stopAudio()
        }
        
        // Use AudioManager for actual playback
        audioManager.togglePlayback(songId: songId, audioURL: song?.audioURL)
        
        // Note: Don't update currentlyPlayingSongId here anymore - let the AudioManager publisher handle it
        
        print("🔥 Final state - currentlyPlayingSongId: \(String(describing: currentlyPlayingSongId))")
    }
    
    private func handleSongSelection(songId: String) {
        print("🎯 handleSongSelection called with songId: \(songId)")
        
        // If the same song is selected, deselect it (and pause if playing)
        if currentlySelectedSongId == songId {
            print("🎯 Deselecting song, setting currentlySelectedSongId to nil")
            currentlySelectedSongId = nil
            
            // If the deselected song was playing, stop it
            if currentlyPlayingSongId == songId {
                print("🎯 Deselected song was playing, stopping it")
                audioManager.stopAudio()
            }
        } else {
            print("🎯 Selecting new song, setting currentlySelectedSongId to: \(songId)")
            
            // If there's a different song currently playing, stop it
            if let playingSongId = currentlyPlayingSongId, playingSongId != songId {
                print("🎯 Stopping currently playing song (\(playingSongId)) because selecting different song")
                audioManager.stopAudio()
            }
            
            // Select the new song
            currentlySelectedSongId = songId
        }
        
        print("🎯 Final state - currentlySelectedSongId: \(String(describing: currentlySelectedSongId)), currentlyPlayingSongId: \(String(describing: currentlyPlayingSongId))")
    }
    
    private func startNewChat() {
        // Reset all chat state to start fresh
        messages = []
        chatText = ""
        isLoading = false
        streamingResponse = ""
        currentSuggestions = []
        latestSongResponse = nil
        chatTitle = nil
        badgeCount = 0
        currentlyPlayingSongId = nil
        currentlySelectedSongId = nil
        isCreatingMore = false
        showGenreSuggestions = false
        selectedGenres = []
        creativeGenreSuggestions = []
        shouldScrollToBeginning = false
        showExtendSheet = false
        showReplaceSheet = false
        showUpsellAlert = false
        isEditingLyrics = false
        lyricsForEditing = ""
        styleForEditing = ""
        isInLyricsFocusMode = false
        currentWorkspaceId = nil
        
        // Clear chat history in service
        chatService.clearChatHistory()
    }
    
    private func handleCreateMore() {
        // Generate more songs directly without showing outgoing message
        guard !isLoading else { return }
        
        // Check if user has enough credits for song generation
        if !creditsManager.hasEnoughCredits(50) {
            // Show insufficient credits message
            let insufficientCreditsMessage = ChatMessage(
                content: "You don't have enough credits to generate more songs. Come back tomorrow for more credits or upgrade to premium.",
                isOutgoing: false
            )
            messages.append(insufficientCreditsMessage)
            return
        }
        
        // Set loading and creating more state
        isLoading = true
        isCreatingMore = true
        streamingResponse = ""
        
        // Send to Gemini directly
        Task {
            do {
                let response = try await chatService.sendMessage("create another version", audioFileName: audioFileName) { chunk in
                    DispatchQueue.main.async {
                        streamingResponse += chunk
                    }
                }
                
                DispatchQueue.main.async {
                    // Parse response to check if it contains song data
                    let responseToCheck = !streamingResponse.isEmpty ? streamingResponse : response
                    
                    if let songResponse = parseSongResponse(from: responseToCheck) {
                        // Handle song generation response
                        latestSongResponse = songResponse
                        currentSuggestions = songResponse.suggestions
                        
                        // Add generated songs to current workspace
                        if let workspaceId = currentWorkspaceId {
                            for song in songResponse.songs {
                                workspaceManager.addSongToWorkspace(workspaceId: workspaceId, song: song)
                            }
                        }
                        
                        // Increment badge count by 2 for each song generation
                        badgeCount += 2
                        
                        // Create a song generation message (will have empty content due to isCreatingMore flag)
                        addSongGenerationMessage(songResponse)
                    }
                    
                    streamingResponse = ""
                    isLoading = false
                    isCreatingMore = false
                }
            } catch {
                DispatchQueue.main.async {
                    print("Error creating more songs: \(error)")
                    streamingResponse = ""
                    isLoading = false
                    isCreatingMore = false
                }
            }
        }
    }
    
    private func getCurrentlyPlayingSongTitle() -> String? {
        guard let songId = currentlyPlayingSongId else { return nil }
        
        // Search through all messages for the song with the matching ID
        for message in messages.reversed() {
            if let songData = message.songData {
                for song in songData.songs {
                    if song.id == songId {
                        return song.title
                    }
                }
            }
        }
        return nil
    }
    
    private func getCurrentlyPlayingSong() -> Song? {
        print("🔍 getCurrentlyPlayingSong called")
        print("🔍 currentlyPlayingSongId: \(String(describing: currentlyPlayingSongId))")
        print("🔍 messages count: \(messages.count)")
        
        guard let songId = currentlyPlayingSongId else { 
            print("🔍 No currentlyPlayingSongId, returning nil")
            return nil 
        }
        
        // Find the song in all messages
        for (messageIndex, message) in messages.enumerated() {
            print("🔍 Checking message \(messageIndex)")
            if let songData = message.songData {
                print("🔍 Message has songData with \(songData.songs.count) songs")
                for (songIndex, song) in songData.songs.enumerated() {
                    print("🔍 Song \(songIndex): id=\(song.id), title=\(song.title)")
                    if song.id == songId {
                        print("🔍 ✅ Found matching song: \(song.title)")
                        return song
                    }
                }
            } else {
                print("🔍 Message \(messageIndex) has no songData")
            }
        }
        
        print("🔍 ❌ No song found with id: \(songId)")
        return nil
    }
    
    private func createGradientForSong(_ song: Song) -> LinearGradient {
        // Use the same gradient creation logic as SongGenerationMessage
        guard let artwork = song.artwork else {
            // Default gradient
            return LinearGradient(
                colors: [
                    Color(red: 0.8, green: 0.4, blue: 0.9),
                    Color(red: 0.4, green: 0.6, blue: 1.0)
                ],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            )
        }
        
        // Create consistent gradient based on artwork string hash (same as SongGenerationMessage)
        let hash = artwork.hashValue
        let seed1 = abs(hash % 1000)
        let seed2 = abs((hash / 1000) % 1000)
        
        return LinearGradient(
            colors: [
                Color(
                    red: 0.3 + (Double(seed1 % 600) / 1000.0),
                    green: 0.3 + (Double((seed1 + 200) % 600) / 1000.0),
                    blue: 0.3 + (Double((seed1 + 400) % 600) / 1000.0)
                ),
                Color(
                    red: 0.3 + (Double(seed2 % 600) / 1000.0),
                    green: 0.3 + (Double((seed2 + 200) % 600) / 1000.0),
                    blue: 0.3 + (Double((seed2 + 400) % 600) / 1000.0)
                )
            ],
            startPoint: .topLeading,
            endPoint: .bottomTrailing
        )
    }
    
    private func getCurrentlySelectedSongTitle() -> String? {
        guard let songId = currentlySelectedSongId else { return nil }
        
        // Search through all messages for the song with the matching ID
        for message in messages.reversed() {
            if let songData = message.songData {
                for song in songData.songs {
                    if song.id == songId {
                        return song.title
                    }
                }
            }
        }
        
        return nil
    }
    
    private func getCurrentlySelectedSong() -> Song? {
        guard let songId = currentlySelectedSongId else { return nil }
        
        // Find the song in all messages
        for message in messages {
            if let songData = message.songData {
                for song in songData.songs {
                    if song.id == songId {
                        return song
                    }
                }
            }
        }
        
        return nil
    }
    
    private func getCurrentlySelectedArtworkGradient() -> LinearGradient? {
        // Get the currently selected song's artwork gradient
        if let currentSong = getCurrentlySelectedSong() {
            return createGradientForSong(currentSong)
        }
        
        return nil
    }
    
    private func isSelectedSongPlaying() -> Bool {
        // Check if the currently selected song is the one that's playing
        guard let selectedSongId = currentlySelectedSongId,
              let playingSongId = currentlyPlayingSongId else {
            return false
        }
        
        return selectedSongId == playingSongId
    }
    
    private func scrollToPlayingSong() {
        // In a production app, you'd implement scroll-to-message functionality
        // For now, this function is a placeholder for future scroll behavior
    }
    
    private func loadCreativeGenreSuggestions() {
        guard !isLoadingGenres else { return }
        
        isLoadingGenres = true
        
        // Get context from the latest song response
        let songContext = getCurrentSongContext()
        let currentGenres = getCurrentGenres()
        
        Task {
            do {
                let suggestions = try await chatService.generateCreativeGenreSuggestions(
                    basedOn: songContext,
                    currentGenres: currentGenres,
                    selectedGenres: selectedGenres
                )
                
                DispatchQueue.main.async {
                    // Replace all suggestions with new contextual ones
                    self.creativeGenreSuggestions = suggestions
                    self.isLoadingGenres = false
                    
                    // Trigger auto-scroll to beginning
                    self.shouldScrollToBeginning = true
                    // Reset scroll trigger after a brief delay
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                        self.shouldScrollToBeginning = false
                    }
                }
            } catch {
                print("Failed to load creative genre suggestions: \(error)")
                DispatchQueue.main.async {
                    // Keep fallback genres on API failure
                    self.creativeGenreSuggestions = []
                    self.isLoadingGenres = false
                }
            }
        }
    }
    
    private func getCurrentSongContext() -> String? {
        // Try to get context from chat title or latest song response
        if let title = chatTitle, !title.isEmpty {
            return title
        }
        
        // Look for patterns in recent messages to understand song context
        for message in messages.reversed() {
            if message.isOutgoing {
                let content = message.content.lowercased()
                if content.contains("song about") || content.contains("make a song") {
                    return message.content
                }
            }
        }
        
        return nil
    }
    
    private func getCurrentGenres() -> [String] {
        // Get genres from the latest song response
        if let songResponse = latestSongResponse,
           let firstSong = songResponse.songs.first {
            return firstSong.genres
        }
        return []
    }
    
    private func getCurrentSongGenres() -> [String] {
        // First priority: get genres from currently playing song
        if let currentSong = getCurrentlyPlayingSong() {
            return currentSong.genres
        }
        
        // Second priority: get genres from latest song response
        return getCurrentGenres()
    }
    
    private func getCurrentWorkspace() -> LibraryWorkspace? {
        guard let workspaceId = currentWorkspaceId else { return nil }
        return workspaceManager.workspaces.first { $0.id == workspaceId }
    }
    
    private func getInitialLyrics() -> String {
        // If lyrics are being edited explicitly, use those
        if !lyricsForEditing.isEmpty {
            return lyricsForEditing
        }
        
        // If a song is currently selected and we have lyrics, use them
        if currentlySelectedSongId != nil, let lyrics = currentLyrics {
            let lyricsText = lyrics.sections.map { section in
                "[\(section.type)]\n\(section.content)"
            }.joined(separator: "\n\n")
            return lyricsText
        }
        
        return ""
    }
    
    private func getInitialStyle() -> String {
        // If style is being edited explicitly, use that
        if !styleForEditing.isEmpty {
            return styleForEditing
        }
        
        // If a song is currently selected, use its genres
        if currentlySelectedSongId != nil {
            let genres = getCurrentSongGenres()
            return genres.joined(separator: ", ")
        }
        
        return ""
    }
    
    private func simulateUploadProgress() {
        // Reset state
        uploadProgress = 0.0
        uploadCompleted = false
        
        // Simulate progress over 2.5 seconds
        let totalDuration = 2.5
        let steps = 50
        let stepDuration = totalDuration / Double(steps)
        
        for i in 1...steps {
            DispatchQueue.main.asyncAfter(deadline: .now() + stepDuration * Double(i)) {
                let progress = Double(i) / Double(steps)
                self.uploadProgress = progress
                
                // Mark as completed when reaching 100%
                if progress >= 1.0 {
                    self.isUploading = false
                    self.uploadCompleted = true
                }
            }
        }
    }
    
    private func handleKeyboardWillShow(notification: Notification) {
        guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
            return
        }
        
        let newKeyboardHeight = keyboardFrame.height
        print("⌨️ Keyboard will show - Height: \(newKeyboardHeight)")
        
        // Reset the tracking flag when keyboard shows
        wasKeyboardVisible = false
        
        // Only auto-scroll if keyboard is appearing (height increasing)
        if newKeyboardHeight > keyboardHeight {
            keyboardHeight = newKeyboardHeight
            
            // Trigger auto-scroll with a small delay to ensure ChatsView is ready
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                print("⌨️ Triggering auto-scroll to bottom")
                shouldAutoScrollToBottom = true
                
                // Reset the trigger after a brief moment
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                    shouldAutoScrollToBottom = false
                }
            }
        } else {
            keyboardHeight = newKeyboardHeight
        }
    }
    
    private func handleKeyboardWillHide() {
        print("⌨️ Keyboard will hide - isChatBarFocused: \(isChatBarFocused)")
        
        // If keyboard is hiding while ChatBar was focused, mark for auto-reopening
        if isChatBarFocused {
            print("⌨️ Setting wasKeyboardVisible = true because keyboard hiding while focused")
            wasKeyboardVisible = true
        }
        
        keyboardHeight = 0
        shouldAutoScrollToBottom = false
    }
    
    private func mightGenerateSong(_ message: String) -> Bool {
        let lowercased = message.lowercased()
        
        // Keywords that typically indicate song generation requests
        let songGenerationKeywords = [
            "create", "make", "generate", "write", "compose", "song", "music",
            "extend", "add verse", "add bridge", "create more", "another version",
            "3rd verse", "bridge", "instrumental", "lyrics", "remix", "change genre"
        ]
        
        // Check if message contains any song generation keywords
        for keyword in songGenerationKeywords {
            if lowercased.contains(keyword) {
                return true
            }
        }
        
        // Also check if this is the first message in an empty chat (likely song creation)
        if messages.isEmpty && !lowercased.isEmpty {
            return true
        }
        
        return false
    }
    
    private func resetExtendMode() {
        isInExtendMode = false
        extensionTime = "0:30s"
        extendModelVersion = "v4.5"
    }

    private func populateFormFromSelectedSong() {
        guard let selectedSong = getCurrentlySelectedSong() else {
            // No song selected, clear the form
            lyricsDescription = ""
            styleDescription = ""
            return
        }

        // Populate lyrics from currentLyrics if available
        if let lyrics = currentLyrics {
            let lyricsText = lyrics.sections.map { section in
                "[\(section.type)]\n\(section.content)"
            }.joined(separator: "\n\n")
            lyricsDescription = lyricsText
        } else {
            lyricsDescription = ""
        }

        // Populate style from song genres
        if !selectedSong.genres.isEmpty {
            styleDescription = selectedSong.genres.joined(separator: ", ")
        } else {
            styleDescription = ""
        }
    }

    private func createChatBar() -> some View {
        let isFullMode = customSheetDetent == .full

        return ChatBar(
            text: $chatText,
            suggestions: [],
            onPlusTap: handlePlusTap,
            onSlidersTap: {
                customSheetDetent = .full
            },
            onUploadTap: handleUploadTap,
            onRecordTap: handleRecordTap,
            onLibraryTap: handleLibraryTap,
            onMicrophoneTap: handleMicrophoneTap,
            onSendTap: handleSendTap,
            onSuggestionTap: handleSuggestionTapWrapper,
            placeholder: "Chat to make music",
            scrollToBeginning: shouldScrollToBeginning,
            isChatBarFocused: $isChatBarFocused,
            audioFileName: audioFileName,
            uploadProgress: uploadProgress,
            isUploading: isUploading,
            uploadCompleted: uploadCompleted,
            onCloseAudio: handleCloseAudio,
            onPlayPauseSelected: handlePlayPauseSelected,
            currentlyPlayingSongTitle: getCurrentlySelectedSongTitle(),
            currentArtworkGradient: getCurrentlySelectedArtworkGradient(),
            isSelectedSongPlaying: isSelectedSongPlaying(),
            onDeselectSong: handleDeselectSong,
            hideTextInput: isFullMode,
            showCreateView: isFullMode,
            showSendButton: isFullMode,
            lyricsDescription: $lyricsDescription,
            styleDescription: $styleDescription,
            selectedModel: selectedModel,
            currentlyPlayingSong: getCurrentlySelectedSong(),
            currentlyPlayingSongId: currentlyPlayingSongId,
            onSongPlayPause: handleSongPlayPause,
            lyricsFocusMode: isInLyricsFocusMode,
            audioManager: audioManager,
            onModelVersionChange: handleModelVersionChange,
            weirdnessValue: $weirdnessValue,
            styleInfluenceValue: $styleInfluenceValue,
            audioInfluenceValue: $audioInfluenceValue,
            vocalGender: $vocalGender
        )
    }

    private func handlePlusTap() {
        print("Plus tapped")
    }

    private func handleUploadTap() {
        print("Upload tapped")
        audioFileName = "AUDIO_1.MP3"
        isUploading = true
        uploadProgress = 0.0
        uploadCompleted = false
        simulateUploadProgress()
    }

    private func handleRecordTap() {
        print("Record tapped")
        showChatSheet = false
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
            showRecordingSheet = true
        }
    }

    private func handleLibraryTap() {
        print("Library tapped")
        navigationPath.append(MainDestination.workspaces)
        badgeCount = 0
        showChatSheet = false
    }

    private func handleMicrophoneTap() {
        print("Microphone tapped")
    }

    private func handleSendTap() {
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
        if customSheetDetent == .full {
            sendCreateMessage()
        } else {
            print("Send: \(chatText)")
            sendMessage()
        }
    }

    private func handleSuggestionTapWrapper(suggestion: String) {
        if showGenreSuggestions {
            handleGenreSuggestionTap(suggestion)
        } else {
            handleSuggestionTap(suggestion)
        }
    }

    private func handleCloseAudio() {
        audioFileName = nil
        uploadProgress = 0.0
        isUploading = false
        uploadCompleted = false
    }

    private func handlePlayPauseSelected() {
        if let selectedSongId = currentlySelectedSongId {
            handleSongPlayPause(songId: selectedSongId)
        }
    }

    private func handleDeselectSong() {
        currentlySelectedSongId = nil
        if currentlyPlayingSongId != nil {
            audioManager.pauseAudio()
            currentlyPlayingSongId = nil
        }
    }

    private func handleModelVersionChange(newModel: String) {
        selectedModel = newModel
    }

}

#Preview {
    ChatView(navigationPath: .constant(NavigationPath()))
}
