package main

import (
	"context"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/anthropics/anthropic-sdk-go"
	"github.com/go-telegram/bot"
	"github.com/go-telegram/bot/models"
	"golang.org/x/sync/errgroup"
)

func (b *Bot) handleVoiceMessage(ctx context.Context, message *models.Message, userMsg Message, chatID, userID int64, username, firstName, lastName string, isPremium bool, languageCode string, messageTime int, businessConnectionID string) {
	if b.config.ElevenLabsAPIKey == "" {
		if err := b.sendResponse(ctx, chatID, "I don't understand voice messages.", businessConnectionID); err != nil {
			ErrorLogger.Printf("Error sending voice-unsupported message: %v", err)
		}
		return
	}

	if !b.hasScope(userID, ScopeTTSUse) {
		if err := b.sendResponse(ctx, chatID, "You don't have permission to use voice features.", businessConnectionID); err != nil {
			ErrorLogger.Printf("Error sending permission denied message: %v", err)
		}
		return
	}

	transcript, err := b.transcribeVoice(ctx, message.Voice.FileID)
	if err != nil {
		ErrorLogger.Printf("Error transcribing voice message from user %d: %v", userID, err)
		if err := b.sendResponse(ctx, chatID, "Sorry, I couldn't understand your voice message.", businessConnectionID); err != nil {
			ErrorLogger.Printf("Error sending transcription error message: %v", err)
		}
		return
	}

	if err := b.db.Model(&userMsg).Update("text", transcript).Error; err != nil {
		ErrorLogger.Printf("Error updating voice transcript in DB: %v", err)
	}
	b.chatMemoriesMu.Lock()
	if mem, exists := b.chatMemories[chatID]; exists {
		for i := len(mem.Messages) - 1; i >= 0; i-- {
			if mem.Messages[i].ID == userMsg.ID {
				mem.Messages[i].Text = transcript
				break
			}
		}
	}
	b.chatMemoriesMu.Unlock()

	chatMemory := b.getOrCreateChatMemory(chatID)
	contextMessages := b.prepareContextMessages(chatMemory)
	response, err := b.getAnthropicResponse(ctx, chatID, contextMessages, false, username, firstName, lastName, isPremium, languageCode, messageTime, nil)
	if err != nil {
		ErrorLogger.Printf("Error getting Anthropic response for voice: %v", err)
		if err := b.sendResponse(ctx, chatID, b.anthropicErrorResponse(err, userID), businessConnectionID); err != nil {
			ErrorLogger.Printf("Error sending anthropic error response: %v", err)
		}
		return
	}

	audioReader, err := b.generateSpeech(ctx, response)
	if err != nil {
		ErrorLogger.Printf("Error generating speech, falling back to text: %v", err)
		if err := b.sendResponse(ctx, chatID, response, businessConnectionID); err != nil {
			ErrorLogger.Printf("Error sending text fallback: %v", err)
		}
		return
	}

	if _, err := b.screenOutgoingMessage(chatID, response); err != nil {
		ErrorLogger.Printf("Error storing assistant voice response: %v", err)
	}

	params := &bot.SendAudioParams{
		ChatID: chatID,
		Audio:  &models.InputFileUpload{Filename: "response.mp3", Data: audioReader},
	}
	if businessConnectionID != "" {
		params.BusinessConnectionID = businessConnectionID
	}
	if _, err := b.tgBot.SendAudio(ctx, params); err != nil {
		ErrorLogger.Printf("Error sending audio to chat %d: %v", chatID, err)
	}
}

func (b *Bot) uploadPhotoFromItem(ctx context.Context, item *models.Message, chatID int64) (string, error) {
	photo := largestPhotoSize(item.Photo)
	data, err := b.downloadTelegramFile(ctx, photo.FileID)
	if err != nil {
		return "", fmt.Errorf("download %s: %w", photo.FileID, err)
	}
	filename := formatUploadFilename(b.botID, chatID, item.ID, "jpg")
	return b.uploadImageToAnthropic(ctx, data, filename, "image/jpeg")
}

func (b *Bot) handlePhotoMessage(
	ctx context.Context,
	items []*models.Message,
	chatID, userID int64,
	username, firstName, lastName string,
	isPremium bool,
	languageCode string,
	messageTime int,
	businessConnectionID string,
) {
	if len(items) == 0 {
		return
	}

	uploaded := make([]string, len(items))
	caption := ""
	g, gctx := errgroup.WithContext(ctx)
	for i, item := range items {
		if item.Caption != "" {
			caption = item.Caption
		}
		if len(item.Photo) == 0 {
			continue
		}
		i, item := i, item
		g.Go(func() error {
			fileID, err := b.uploadPhotoFromItem(gctx, item, chatID)
			if err != nil {
				return err
			}
			uploaded[i] = fileID
			return nil
		})
	}
	if err := g.Wait(); err != nil {
		ErrorLogger.Printf("[%s] photo upload failed: %v", b.config.ID, err)
		var successful []string
		for _, fid := range uploaded {
			if fid != "" {
				successful = append(successful, fid)
			}
		}
		b.compensatingDelete(ctx, successful)
		if sendErr := b.sendResponse(ctx, chatID, "Sorry, I couldn't process one of your images.", businessConnectionID); sendErr != nil {
			ErrorLogger.Printf("Error sending photo failure message: %v", sendErr)
		}
		return
	}
	finalUploaded := make([]string, 0, len(uploaded))
	for _, fid := range uploaded {
		if fid != "" {
			finalUploaded = append(finalUploaded, fid)
		}
	}
	if len(finalUploaded) == 0 {
		return
	}

	chatMemory := b.getOrCreateChatMemory(chatID)
	userMessage := b.createMessage(chatID, userID, username, "user", caption, true)
	userMessage.ImageFileIDs = finalUploaded
	if err := b.storeMessage(&userMessage); err != nil {
		b.compensatingDelete(ctx, finalUploaded)
		ErrorLogger.Printf("[%s] store photo message failed: %v", b.config.ID, err)
		if sendErr := b.sendResponse(ctx, chatID, "Sorry, I had trouble saving your message.", businessConnectionID); sendErr != nil {
			ErrorLogger.Printf("Error sending store failure message: %v", sendErr)
		}
		return
	}
	b.addMessageToChatMemory(chatMemory, userMessage)

	contextMessages := b.prepareContextMessages(chatMemory)
	joined, err := b.getAnthropicResponse(
		ctx, chatID, contextMessages, false,
		username, firstName, lastName, isPremium, languageCode, messageTime,
		func(seg string) error {
			return b.sendOneSegment(ctx, chatID, seg, businessConnectionID)
		},
	)
	if err != nil {
		ErrorLogger.Printf("Error getting Anthropic response for photo: %v", err)
		if sendErr := b.sendResponse(ctx, chatID, b.anthropicErrorResponse(err, userID), businessConnectionID); sendErr != nil {
			ErrorLogger.Printf("Error sending anthropic error response: %v", sendErr)
		}
		return
	}
	if _, storeErr := b.screenOutgoingMessage(chatID, joined); storeErr != nil {
		ErrorLogger.Printf("Error recording assistant turn: %v", storeErr)
	}
}

func (b *Bot) anthropicErrorResponse(err error, userID int64) string {
	isElevated := b.hasScope(userID, ScopeModelSet)

	if errors.Is(err, ErrModelNotFound) && isElevated {
		return fmt.Sprintf(
			"⚠️ Model `%s` is no longer available (deprecated or removed by Anthropic).\n"+
				"Use /set_model <model-id> to switch. Current models: https://platform.claude.com/docs/en/about-claude/models/overview",
			b.config.Model,
		)
	}

	if isElevated {
		var apiErr *anthropic.Error
		if errors.As(err, &apiErr) {
			body := apiErr.RawJSON()
			if len(body) > 800 {
				body = body[:800] + "...(truncated)"
			}
			out := fmt.Sprintf("⚠️ Anthropic API error %d:\n%s", apiErr.StatusCode, body)
			if apiErr.RequestID != "" {
				out += fmt.Sprintf("\nRequest-ID: %s", apiErr.RequestID)
			}
			return out
		}
		return fmt.Sprintf("⚠️ Anthropic call failed: %v", err)
	}

	return "I'm sorry, I'm having trouble processing your request right now."
}

func (b *Bot) handleUpdate(ctx context.Context, tgBot *bot.Bot, update *models.Update) {
	var message *models.Message

	if update.Message != nil {
		message = update.Message
	} else if update.BusinessMessage != nil {
		message = update.BusinessMessage
	} else {
		return
	}

	var businessConnectionID string
	if update.BusinessConnection != nil {
		businessConnectionID = update.BusinessConnection.ID
	} else if message.BusinessConnectionID != "" {
		businessConnectionID = message.BusinessConnectionID
	}

	if message.From == nil {
		return
	}

	chatID := message.Chat.ID
	userID := message.From.ID
	username := message.From.Username
	firstName := message.From.FirstName
	lastName := message.From.LastName
	languageCode := message.From.LanguageCode
	isPremium := message.From.IsPremium
	messageTime := message.Date
	text := message.Text

	var isOwner bool
	if b.db.Where("telegram_id = ? AND bot_id = ? AND is_owner = ?", userID, b.botID, true).First(&User{}).Error == nil {
		isOwner = true
	}

	user, err := b.getOrCreateUser(userID, username, isOwner)
	if err != nil {
		ErrorLogger.Printf("Error getting or creating user: %v", err)
		return
	}

	if user.Username != username {
		user.Username = username
		if err := b.db.Save(&user).Error; err != nil {
			ErrorLogger.Printf("Error updating user username: %v", err)
		}
	}

	if message.MediaGroupID != "" && len(message.Photo) > 0 {
		b.bufferAlbumItem(ctx, message, chatID, userID, username, firstName, lastName,
			isPremium, languageCode, messageTime, businessConnectionID)
		return
	}
	if len(message.Photo) > 0 {
		if !b.checkRateLimits(userID) {
			b.sendRateLimitExceededMessage(ctx, chatID, businessConnectionID)
			return
		}
		b.handlePhotoMessage(ctx, []*models.Message{message},
			chatID, userID, username, firstName, lastName,
			isPremium, languageCode, messageTime,
			businessConnectionID)
		return
	}

	userMsg, err := b.screenIncomingMessage(message)
	if err != nil {
		ErrorLogger.Printf("Error storing user message: %v", err)
		return
	}

	if message.Entities != nil {
		for _, entity := range message.Entities {
			if entity.Type == "bot_command" {
				command := strings.TrimSpace(message.Text[entity.Offset : entity.Offset+entity.Length])
				switch command {
				case "/stats":
					parts := strings.Fields(message.Text)

					if len(parts) == 1 {
						b.sendStats(ctx, chatID, userID, 0, businessConnectionID)
						return
					}

					if len(parts) >= 2 && parts[1] == "user" {
						targetUserID := userID

						if len(parts) >= 3 {
							var parseErr error
							targetUserID, parseErr = strconv.ParseInt(parts[2], 10, 64)
							if parseErr != nil {
								InfoLogger.Printf("User %d provided invalid user ID format: %s", userID, parts[2])
								if err := b.sendResponse(ctx, chatID, "Invalid user ID format. Usage: /stats user [user_id]", businessConnectionID); err != nil {
									ErrorLogger.Printf("Error sending response: %v", err)
								}
								return
							}
						}

						b.sendStats(ctx, chatID, userID, targetUserID, businessConnectionID)
						return
					}

					if err := b.sendResponse(ctx, chatID, "Invalid command format. Usage: /stats or /stats user [user_id]", businessConnectionID); err != nil {
						ErrorLogger.Printf("Error sending response: %v", err)
					}
					return
				case "/whoami":
					b.sendWhoAmI(ctx, chatID, userID, username, businessConnectionID)
					return
				case "/clear":
					parts := strings.Fields(message.Text)
					var targetUserID, targetChatID int64
					if len(parts) > 1 {
						var parseErr error
						targetUserID, parseErr = strconv.ParseInt(parts[1], 10, 64)
						if parseErr != nil {
							InfoLogger.Printf("User %d provided invalid user ID format: %s", userID, parts[1])
							if err := b.sendResponse(ctx, chatID, "Invalid user ID format. Usage: /clear [user_id] [chat_id]", businessConnectionID); err != nil {
								ErrorLogger.Printf("Error sending response: %v", err)
							}
							return
						}
					}
					if len(parts) > 2 {
						var parseErr error
						targetChatID, parseErr = strconv.ParseInt(parts[2], 10, 64)
						if parseErr != nil {
							InfoLogger.Printf("User %d provided invalid chat ID format: %s", userID, parts[2])
							if err := b.sendResponse(ctx, chatID, "Invalid chat ID format. Usage: /clear [user_id] [chat_id]", businessConnectionID); err != nil {
								ErrorLogger.Printf("Error sending response: %v", err)
							}
							return
						}
					}
					b.clearChatHistory(ctx, chatID, userID, targetUserID, targetChatID, businessConnectionID, false)
					return
				case "/set_model":
					if !b.hasScope(userID, ScopeModelSet) {
						if err := b.sendResponse(ctx, chatID, "Permission denied. Only admins and owners can change the model.", businessConnectionID); err != nil {
							ErrorLogger.Printf("Error sending response: %v", err)
						}
						return
					}
					parts := strings.Fields(message.Text)
					if len(parts) < 2 || strings.TrimSpace(parts[1]) == "" {
						if err := b.sendResponse(ctx, chatID, "Usage: /set_model <model-id>", businessConnectionID); err != nil {
							ErrorLogger.Printf("Error sending response: %v", err)
						}
						return
					}
					newModel := strings.TrimSpace(parts[1])
					if err := b.config.PersistModel(newModel); err != nil {
						ErrorLogger.Printf("Failed to persist model change: %v", err)
						if err := b.sendResponse(ctx, chatID, fmt.Sprintf("Model updated in memory to `%s`, but failed to save to config file: %v", newModel, err), businessConnectionID); err != nil {
							ErrorLogger.Printf("Error sending response: %v", err)
						}
						return
					}
					InfoLogger.Printf("Model changed to %s by user %d", newModel, userID)
					if err := b.sendResponse(ctx, chatID, fmt.Sprintf("✅ Model updated to `%s` and saved to config.", newModel), businessConnectionID); err != nil {
						ErrorLogger.Printf("Error sending response: %v", err)
					}
					return
				case "/clear_hard":
					parts := strings.Fields(message.Text)
					var targetUserID, targetChatID int64
					if len(parts) > 1 {
						var parseErr error
						targetUserID, parseErr = strconv.ParseInt(parts[1], 10, 64)
						if parseErr != nil {
							InfoLogger.Printf("User %d provided invalid user ID format: %s", userID, parts[1])
							if err := b.sendResponse(ctx, chatID, "Invalid user ID format. Usage: /clear_hard [user_id] [chat_id]", businessConnectionID); err != nil {
								ErrorLogger.Printf("Error sending response: %v", err)
							}
							return
						}
					}
					if len(parts) > 2 {
						var parseErr error
						targetChatID, parseErr = strconv.ParseInt(parts[2], 10, 64)
						if parseErr != nil {
							InfoLogger.Printf("User %d provided invalid chat ID format: %s", userID, parts[2])
							if err := b.sendResponse(ctx, chatID, "Invalid chat ID format. Usage: /clear_hard [user_id] [chat_id]", businessConnectionID); err != nil {
								ErrorLogger.Printf("Error sending response: %v", err)
							}
							return
						}
					}
					b.clearChatHistory(ctx, chatID, userID, targetUserID, targetChatID, businessConnectionID, true)
					return
				}
			}
		}
	}

	if !b.checkRateLimits(userID) {
		b.sendRateLimitExceededMessage(ctx, chatID, businessConnectionID)
		return
	}

	if message.Voice != nil {
		b.handleVoiceMessage(ctx, message, userMsg, chatID, userID, username, firstName, lastName, isPremium, languageCode, messageTime, businessConnectionID)
		return
	}

	chatMemory := b.getOrCreateChatMemory(chatID)
	contextMessages := b.prepareContextMessages(chatMemory)

	if message.Sticker != nil {
		b.handleStickerMessage(ctx, chatID, userMsg, message, contextMessages, businessConnectionID)
		return
	}

	if text == "" {
		InfoLogger.Printf("Received a non-text message from user %d in chat %d", userID, chatID)
		return
	}

	isEmojiOnly := isOnlyEmojis(text)

	joined, err := b.getAnthropicResponse(
		ctx, chatID, contextMessages, isEmojiOnly,
		username, firstName, lastName, isPremium, languageCode, messageTime,
		func(seg string) error {
			return b.sendOneSegment(ctx, chatID, seg, businessConnectionID)
		},
	)
	if err != nil {
		ErrorLogger.Printf("Error getting Anthropic response: %v", err)
		if sendErr := b.sendResponse(ctx, chatID, b.anthropicErrorResponse(err, userID), businessConnectionID); sendErr != nil {
			ErrorLogger.Printf("Error sending response: %v", sendErr)
		}
		return
	}

	if _, storeErr := b.screenOutgoingMessage(chatID, joined); storeErr != nil {
		ErrorLogger.Printf("Error recording assistant turn: %v", storeErr)
	}
}

func (b *Bot) sendRateLimitExceededMessage(ctx context.Context, chatID int64, businessConnectionID string) {
	if err := b.sendResponse(ctx, chatID, "Rate limit exceeded. Please try again later.", businessConnectionID); err != nil {
		ErrorLogger.Printf("Error sending rate limit exceeded message: %v", err)
	}
}

func (b *Bot) handleStickerMessage(ctx context.Context, chatID int64, userMessage Message, message *models.Message, contextMessages []anthropic.BetaMessageParam, businessConnectionID string) {

	response, err := b.generateStickerResponse(ctx, userMessage, contextMessages)
	if err != nil {
		ErrorLogger.Printf("Error generating sticker response: %v", err)
		if message.Sticker.IsAnimated {
			response = "Wow, that's a cool animated sticker!"
		} else if message.Sticker.IsVideo {
			response = "Interesting video sticker!"
		} else {
			response = "That's a cool sticker!"
		}
	}

	if err := b.sendResponse(ctx, chatID, response, businessConnectionID); err != nil {
		ErrorLogger.Printf("Error sending response: %v", err)
		return
	}
}

func (b *Bot) generateStickerResponse(ctx context.Context, message Message, contextMessages []anthropic.BetaMessageParam) (string, error) {
	if message.StickerFileID != "" {
		messageTime := int(message.Timestamp.Unix())
		response, err := b.getAnthropicResponse(ctx, message.ChatID, contextMessages, true, message.Username, "", "", false, "", messageTime, nil)
		if err != nil {
			return "", err
		}
		return response, nil
	}

	return "Hmm, that's interesting!", nil
}

func (b *Bot) clearChatHistory(ctx context.Context, chatID int64, currentUserID int64, targetUserID int64, targetChatID int64, businessConnectionID string, hardDelete bool) {
	if targetUserID != 0 && targetUserID != currentUserID {
		requiredScope := ScopeHistoryClearAny
		if hardDelete {
			requiredScope = ScopeHistoryClearHardAny
		}
		if !b.hasScope(currentUserID, requiredScope) {
			InfoLogger.Printf("User %d attempted to clear history for user %d without permission", currentUserID, targetUserID)
			if err := b.sendResponse(ctx, chatID, "Permission denied. Only admins and owners can clear other users' histories.", businessConnectionID); err != nil {
				ErrorLogger.Printf("Error sending response: %v", err)
			}
			return
		}

		var targetUser User
		err := b.db.Where("telegram_id = ? AND bot_id = ?", targetUserID, b.botID).First(&targetUser).Error
		if err != nil {
			ErrorLogger.Printf("Error finding target user %d: %v", targetUserID, err)
			if err := b.sendResponse(ctx, chatID, fmt.Sprintf("User with ID %d not found.", targetUserID), businessConnectionID); err != nil {
				ErrorLogger.Printf("Error sending response: %v", err)
			}
			return
		}
	} else {
		targetUserID = currentUserID
	}

	var err error
	if hardDelete {
		if targetUserID == currentUserID {
			err = b.hardDeleteScope(ctx, "chat_id = ? AND bot_id = ?", chatID, b.botID)
			InfoLogger.Printf("User %d permanently deleted their own chat history in chat %d", currentUserID, chatID)
		} else {
			if targetChatID != 0 {
				err = b.hardDeleteScope(ctx, "chat_id = ? AND bot_id = ?", targetChatID, b.botID)
				InfoLogger.Printf("Admin/owner %d permanently deleted chat history for user %d in chat %d", currentUserID, targetUserID, targetChatID)
			} else {
				err = b.hardDeleteScope(ctx,
					"bot_id = ? AND (user_id = ? OR (chat_id = ? AND is_user = ?))",
					b.botID, targetUserID, targetUserID, false)
				InfoLogger.Printf("Admin/owner %d permanently deleted all chat history for user %d", currentUserID, targetUserID)
			}
		}
	} else {
		if targetUserID == currentUserID {
			err = b.db.Where("chat_id = ? AND bot_id = ?", chatID, b.botID).Delete(&Message{}).Error
			InfoLogger.Printf("User %d soft deleted their own chat history in chat %d", currentUserID, chatID)
		} else {
			if targetChatID != 0 {
				err = b.db.Where("chat_id = ? AND bot_id = ?", targetChatID, b.botID).Delete(&Message{}).Error
				InfoLogger.Printf("Admin/owner %d soft deleted chat history for user %d in chat %d", currentUserID, targetUserID, targetChatID)
			} else {
				err = b.db.Where("bot_id = ? AND user_id = ?", b.botID, targetUserID).Delete(&Message{}).Error
				if err == nil {
					err = b.db.Where("chat_id = ? AND bot_id = ? AND is_user = ?", targetUserID, b.botID, false).Delete(&Message{}).Error
				}
				InfoLogger.Printf("Admin/owner %d soft deleted all chat history for user %d", currentUserID, targetUserID)
			}
		}
	}

	if err != nil {
		ErrorLogger.Printf("Error clearing chat history: %v", err)
		if err := b.sendResponse(ctx, chatID, "Sorry, I couldn't clear the chat history.", businessConnectionID); err != nil {
			ErrorLogger.Printf("Error sending response: %v", err)
		}
		return
	}

	b.chatMemoriesMu.Lock()
	if targetUserID == currentUserID {
		delete(b.chatMemories, chatID)
	} else if targetChatID != 0 {
		delete(b.chatMemories, targetChatID)
	} else {
		delete(b.chatMemories, targetUserID)
	}
	b.chatMemoriesMu.Unlock()

	var confirmationMessage string
	if targetUserID == currentUserID {
		confirmationMessage = "Your chat history has been cleared."
	} else {
		var targetUser User
		err := b.db.Where("telegram_id = ? AND bot_id = ?", targetUserID, b.botID).First(&targetUser).Error
		if err == nil && targetUser.Username != "" {
			confirmationMessage = fmt.Sprintf("Chat history for user @%s (ID: %d) has been cleared.", targetUser.Username, targetUserID)
		} else {
			confirmationMessage = fmt.Sprintf("Chat history for user with ID %d has been cleared.", targetUserID)
		}
	}

	if err := b.sendResponse(ctx, chatID, confirmationMessage, businessConnectionID); err != nil {
		ErrorLogger.Printf("Error sending response: %v", err)
	}
}
