package chat

import (
	"errors"
	"fmt"
	"time"

	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"hfb_sys/backend/internal/model"
)

// 会话类型常量
const (
	ConversationTypeOrderGroup   = "order_group"
	ConversationTypeListingGroup = "listing_group"
	ConversationTypeGeneralSupport = "general_support"
)

var (
	ErrListingConversationExists = errors.New("发布群已存在")
)

// EnsureListingConversation 确保发布群存在(幂等)
func EnsureListingConversation(tx *gorm.DB, listing model.RentalListing) (*model.ChatConversation, error) {
	// 1. 幂等查重
	var existing model.ChatConversation
	err := tx.Where("listing_id = ?", listing.ID).First(&existing).Error
	if err == nil {
		return &existing, nil
	}
	if !errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, err
	}

	// 2. 建会话
	now := time.Now()
	conversation := model.ChatConversation{
		ListingID: &listing.ID,
		Type:      ConversationTypeListingGroup,
		Title:     listingConversationTitle(listing),
		Status:    "active",
	}
	if err := tx.Create(&conversation).Error; err != nil {
		return nil, err
	}

	// 3. 写参与者: 号主 + 客服
	participants := []model.ChatParticipant{
		{
			ConversationID:  conversation.ID,
			ParticipantType: "user",
			ParticipantID:   listing.OwnerID,
			Role:            "owner",
			JoinedAt:        now,
		},
	}

	// 获取客服
	if supportID := defaultSupportAdminID(tx); supportID > 0 {
		participants = append(participants, model.ChatParticipant{
			ConversationID:  conversation.ID,
			ParticipantType: "admin",
			ParticipantID:   supportID,
			Role:            "support",
			JoinedAt:        now,
		})
	}

	for _, participant := range participants {
		if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&participant).Error; err != nil {
			return nil, err
		}
	}

	// 4. 取二维码(带行锁)
	var qrcode *model.ChatQrCode
	var qrcodeImageURL string
	qrcodeObj, err := fetchUnusedQrCode(tx)
	if err != nil {
		return nil, err
	}
	if qrcodeObj != nil {
		qrcode = qrcodeObj
		qrcodeImageURL = qrcode.ImageURL
		// 标记二维码为已使用
		if err := markQrCodeAsUsed(tx, qrcode.ID, conversation.ID); err != nil {
			return nil, err
		}
	}

	// 5. 发欢迎语
	welcomeMessage := getListingGroupWelcomeMessage(tx)
	if err := sendSystemMessage(tx, conversation.ID, welcomeMessage); err != nil {
		return nil, err
	}

	// 6. 发二维码图片(如果有)
	if qrcodeImageURL != "" {
		if err := sendQrCodeImage(tx, conversation.ID, qrcodeImageURL); err != nil {
			return nil, err
		}
	} else {
		// 无二维码,发提示
		noQrTip := "客服企业微信群二维码补充中，请稍后在群内关注"
		if err := sendSystemMessage(tx, conversation.ID, noQrTip); err != nil {
			return nil, err
		}
	}

	// 7. 库存预警检查
	if qrcode != nil {
		if err := checkQrCodeStockAndAlert(tx, &conversation); err != nil {
			// 预警失败不阻塞建群,仅记录日志
			// TODO: 添加日志
		}
	}

	return &conversation, nil
}

// AddRenterToListingConversation 拉租客进发布群
func AddRenterToListingConversation(tx *gorm.DB, listingID uint64, renterID uint64, orderNo string) error {
	// 1. 查找发布群
	var conv model.ChatConversation
	err := tx.Where("listing_id = ?", listingID).First(&conv).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			// 历史数据无发布群,优雅跳过
			return nil
		}
		return err
	}

	// 2. 幂等插入租客
	now := time.Now()
	participant := model.ChatParticipant{
		ConversationID:  conv.ID,
		ParticipantType: "user",
		ParticipantID:   renterID,
		Role:            "renter",
		JoinedAt:        now, // 关键: 记录加入时间,用于消息可见性过滤
	}

	if err := tx.Clauses(clause.OnConflict{DoNothing: true}).Create(&participant).Error; err != nil {
		return err
	}

	// 3. 发系统消息
	message := "租客已加入群聊(订单 " + orderNo + ")"
	return sendSystemMessage(tx, conv.ID, message)
}

// RemoveRenterFromListingConversation 移出租客
func RemoveRenterFromListingConversation(tx *gorm.DB, listingID uint64, renterID uint64) error {
	// 1. 查找发布群
	var conv model.ChatConversation
	err := tx.Where("listing_id = ?", listingID).First(&conv).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			// 无发布群,跳过
			return nil
		}
		return err
	}

	// 2. 删除租客参与者记录
	result := tx.Where("conversation_id = ? AND participant_type = ? AND participant_id = ? AND role = ?",
		conv.ID, "user", renterID, "renter").
		Delete(&model.ChatParticipant{})

	if result.Error != nil {
		return result.Error
	}

	// 3. 发系统消息(如果确实删除了)
	if result.RowsAffected > 0 {
		message := "订单已结束，租客已退出群聊"
		return sendSystemMessage(tx, conv.ID, message)
	}

	return nil
}

// 辅助函数

func listingConversationTitle(listing model.RentalListing) string {
	return "账号群 " + listing.ListingNo
}

func getListingGroupWelcomeMessage(tx *gorm.DB) string {
	defaultMsg := "欢迎加入账号群！请号主扫描下方二维码加入企业微信群，方便客服与您及时联系。"

	var cfg model.SystemConfig
	if err := tx.Where("`key` = ?", "chat.listing_group_welcome").First(&cfg).Error; err == nil && cfg.Value != "" {
		return cfg.Value
	}

	return defaultMsg
}

func sendSystemMessage(tx *gorm.DB, conversationID uint64, content string) error {
	message := model.ChatMessage{
		ConversationID: conversationID,
		SenderType:     "system",
		SenderRole:     "system",
		ContentType:    "system",
		Content:        content,
		AttachmentURLS: emptyJSONList(),
	}

	if err := tx.Create(&message).Error; err != nil {
		return err
	}

	// 更新会话的最后消息
	return updateConversationLastMessage(tx, conversationID, &message)
}

func sendQrCodeImage(tx *gorm.DB, conversationID uint64, imageURL string) error {
	attachmentURLs := `["` + imageURL + `"]`
	content := "👇 请扫码加入企业微信群"

	message := model.ChatMessage{
		ConversationID: conversationID,
		SenderType:     "system",
		SenderRole:     "system",
		ContentType:    "image",
		Content:        content,
		AttachmentURLS: []byte(attachmentURLs),
	}

	if err := tx.Create(&message).Error; err != nil {
		return err
	}

	// 更新会话的最后消息
	return updateConversationLastMessage(tx, conversationID, &message)
}

func updateConversationLastMessage(tx *gorm.DB, conversationID uint64, message *model.ChatMessage) error {
	updates := map[string]interface{}{
		"last_message_id":      message.ID,
		"last_message_preview": truncatePreview(message.Content),
		"last_message_at":      message.CreatedAt,
	}

	return tx.Model(&model.ChatConversation{}).
		Where("id = ?", conversationID).
		Updates(updates).Error
}

func fetchUnusedQrCode(tx *gorm.DB) (*model.ChatQrCode, error) {
	var qrcode model.ChatQrCode
	now := time.Now()

	err := tx.Where("status = ?", QrCodeStatusUnused).
		Where("expires_at IS NULL OR expires_at > ?", now).
		Order("id ASC").
		Limit(1).
		Clauses(clause.Locking{Strength: "UPDATE"}).
		First(&qrcode).Error

	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, nil // 无可用二维码,返回 nil 而非错误
		}
		return nil, err
	}

	return &qrcode, nil
}

func markQrCodeAsUsed(tx *gorm.DB, qrcodeID uint64, conversationID uint64) error {
	now := time.Now()
	return tx.Model(&model.ChatQrCode{}).
		Where("id = ?", qrcodeID).
		Updates(map[string]interface{}{
			"status":          QrCodeStatusUsed,
			"conversation_id": conversationID,
			"used_at":         now,
		}).Error
}

func checkQrCodeStockAndAlert(tx *gorm.DB, conversation *model.ChatConversation) error {
	// 获取库存阈值
	threshold := int64(5)
	var cfg model.SystemConfig
	if err := tx.Where("`key` = ?", "chat.qrcode_low_stock_threshold").First(&cfg).Error; err == nil && cfg.Value != "" {
		// 尝试解析为数字
		if val, err := parseThreshold(cfg.Value); err == nil {
			threshold = val
		}
	}

	// 统计未使用的二维码数量
	var count int64
	if err := tx.Model(&model.ChatQrCode{}).
		Where("status = ?", QrCodeStatusUnused).
		Count(&count).Error; err != nil {
		return err
	}

	// 如果低于阈值,发送预警给所有客服
	if count <= threshold {
		// 查询所有 cs 角色的客服
		var csAdmins []model.AdminUser
		if err := tx.Table("admin_users").
			Joins("JOIN admin_user_roles ON admin_users.id = admin_user_roles.admin_user_id").
			Joins("JOIN roles ON admin_user_roles.role_id = roles.id").
			Where("roles.code = ? AND admin_users.status = ?", "cs", "active").
			Select("admin_users.id").
			Find(&csAdmins).Error; err != nil {
			return err
		}

		// 构造预警消息
		alertContent := fmt.Sprintf("企业微信群二维码库存不足（剩余 %d 张），请及时补充", count)

		// 发送站内信给所有客服
		var entries []interface{}
		for _, admin := range csAdmins {
			entries = append(entries, map[string]interface{}{
				"admin_user_id": admin.ID,
				"type":          "system",
				"title":         "二维码库存预警",
				"content":       alertContent,
				"is_read":       false,
				"created_at":    time.Now(),
				"updated_at":    time.Now(),
			})
		}

		if len(entries) > 0 {
			// 批量插入通知
			if err := tx.Table("admin_notifications").Create(entries).Error; err != nil {
				return err
			}
		}
	}

	return nil
}

func parseThreshold(value string) (int64, error) {
	var threshold int64
	if _, err := fmt.Sscanf(value, "%d", &threshold); err != nil {
		return 0, err
	}
	return threshold, nil
}
