package chat

import (
	"context"
	"errors"
	"time"

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

// QrCodeStatus 二维码状态常量
const (
	QrCodeStatusUnused   = "unused"
	QrCodeStatusUsed     = "used"
	QrCodeStatusDisabled = "disabled"

	qrCodeOCRTokenConfigKey  = "integration.paddle_ocr_token"
	qrCodeOCRJobURLConfigKey = "integration.paddle_ocr_job_url"
	qrCodeOCRModelConfigKey  = "integration.paddle_ocr_model"
	defaultQrCodeOCRJobURL   = "https://paddleocr.aistudio-app.com/api/v2/ocr/jobs"
	defaultQrCodeOCRModel    = "PaddleOCR-VL-1.6"
)

var (
	ErrQrCodeNotFound       = errors.New("二维码不存在")
	ErrQrCodeCannotReenable = errors.New("已发放的二维码不能改回待用")
)

// CreateQrCodeRequest 创建二维码请求
type CreateQrCodeRequest struct {
	ImageURL  string     `json:"image_url" binding:"required"`
	GroupName string     `json:"group_name"`
	Note      string     `json:"note"`
	ExpiresAt *time.Time `json:"expires_at"`
}

// BatchCreateQrCodeRequest 批量创建二维码请求
type BatchCreateQrCodeRequest struct {
	Items []CreateQrCodeRequest `json:"items" binding:"required,min=1,max=20"`
}

// BatchDeleteQrCodeRequest 批量删除二维码请求
type BatchDeleteQrCodeRequest struct {
	IDs []uint64 `json:"ids" binding:"required,min=1,max=100"`
}

// UpdateQrCodeRequest 更新二维码请求
type UpdateQrCodeRequest struct {
	ImageURL       *string    `json:"image_url"`
	GroupName      *string    `json:"group_name"`
	Note           *string    `json:"note"`
	Status         *string    `json:"status"`
	WecomRenamed   *bool      `json:"wecom_renamed"`
	ExpiresAt      *time.Time `json:"expires_at"`
	ClearExpiresAt bool       `json:"clear_expires_at"`
}

// QrCodeListRequest 列表查询请求
type QrCodeListRequest struct {
	Status string `form:"status"`
	Page   int    `form:"page"`
	Limit  int    `form:"limit"`
}

// QrCodeStats 二维码统计
type QrCodeStats struct {
	UnusedCount   int64 `json:"unused_count"`
	UsedCount     int64 `json:"used_count"`
	DisabledCount int64 `json:"disabled_count"`
	TotalCount    int64 `json:"total_count"`
}

// QrCodeListItem 二维码列表项
type QrCodeListItem struct {
	model.ChatQrCode
	BoundConversationTitle string `json:"bound_conversation_title"`
}

// QrCodeOCRConfig 二维码 OCR 调用配置
type QrCodeOCRConfig struct {
	Token  string `json:"token"`
	JobURL string `json:"job_url"`
	Model  string `json:"model"`
}

// CreateQrCode 创建二维码
func (r *Repository) CreateQrCode(ctx context.Context, adminID uint64, req CreateQrCodeRequest) (*model.ChatQrCode, error) {
	var qrcode model.ChatQrCode
	var deliveredMessages []model.ChatMessage
	err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		qrcode = model.ChatQrCode{
			ImageURL:  req.ImageURL,
			GroupName: req.GroupName,
			Status:    QrCodeStatusUnused,
			CreatedBy: adminID,
			Note:      req.Note,
			ExpiresAt: req.ExpiresAt,
		}

		// 如果未指定过期时间，默认7天后过期
		if qrcode.ExpiresAt == nil {
			expires := time.Now().Add(7 * 24 * time.Hour)
			qrcode.ExpiresAt = &expires
		}

		if err := tx.Create(&qrcode).Error; err != nil {
			return err
		}
		var err error
		deliveredMessages, err = deliverPendingQrCodes(tx)
		return err
	})
	if err != nil {
		return nil, err
	}
	r.notifyDeliveredQrCodeMessages(deliveredMessages)

	return &qrcode, nil
}

// BatchCreateQrCode 批量创建二维码
func (r *Repository) BatchCreateQrCode(ctx context.Context, adminID uint64, req BatchCreateQrCodeRequest) ([]model.ChatQrCode, error) {
	var qrcodes []model.ChatQrCode
	var deliveredMessages []model.ChatMessage
	defaultExpires := time.Now().Add(7 * 24 * time.Hour)

	err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		for _, item := range req.Items {
			qr := model.ChatQrCode{
				ImageURL:  item.ImageURL,
				GroupName: item.GroupName,
				Status:    QrCodeStatusUnused,
				CreatedBy: adminID,
				Note:      item.Note,
				ExpiresAt: item.ExpiresAt,
			}
			if qr.ExpiresAt == nil {
				qr.ExpiresAt = &defaultExpires
			}
			qrcodes = append(qrcodes, qr)
		}

		if err := tx.Create(&qrcodes).Error; err != nil {
			return err
		}
		var err error
		deliveredMessages, err = deliverPendingQrCodes(tx)
		return err
	})
	if err != nil {
		return nil, err
	}
	r.notifyDeliveredQrCodeMessages(deliveredMessages)

	return qrcodes, nil
}

// ListQrCodes 列表查询二维码
func (r *Repository) ListQrCodes(ctx context.Context, req QrCodeListRequest) ([]QrCodeListItem, int64, error) {
	if req.Page < 1 {
		req.Page = 1
	}
	if req.Limit < 1 || req.Limit > 100 {
		req.Limit = 20
	}

	query := r.db.WithContext(ctx).Model(&model.ChatQrCode{})

	// 状态过滤
	if req.Status != "" {
		query = query.Where("status = ?", req.Status)
	}

	// 统计总数
	var total int64
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 查询列表
	var qrcodes []QrCodeListItem
	offset := (req.Page - 1) * req.Limit
	if err := r.db.WithContext(ctx).
		Table("chat_qrcode_pool AS q").
		Select("q.*, COALESCE(c.title, '') AS bound_conversation_title").
		Joins("LEFT JOIN chat_conversations AS c ON c.id = q.conversation_id").
		Scopes(func(db *gorm.DB) *gorm.DB {
			if req.Status != "" {
				return db.Where("q.status = ?", req.Status)
			}
			return db
		}).
		Order("q.id DESC").
		Offset(offset).
		Limit(req.Limit).
		Scan(&qrcodes).Error; err != nil {
		return nil, 0, err
	}

	return qrcodes, total, nil
}

// GetQrCodeStats 获取二维码统计信息
func (r *Repository) GetQrCodeStats(ctx context.Context) (*QrCodeStats, error) {
	stats := &QrCodeStats{}
	now := time.Now()

	if err := r.db.WithContext(ctx).Model(&model.ChatQrCode{}).Count(&stats.TotalCount).Error; err != nil {
		return nil, err
	}
	if err := r.db.WithContext(ctx).
		Model(&model.ChatQrCode{}).
		Where("status = ?", QrCodeStatusUsed).
		Count(&stats.UsedCount).Error; err != nil {
		return nil, err
	}
	if err := r.db.WithContext(ctx).
		Model(&model.ChatQrCode{}).
		Where("status = ?", QrCodeStatusDisabled).
		Count(&stats.DisabledCount).Error; err != nil {
		return nil, err
	}
	if err := r.db.WithContext(ctx).
		Model(&model.ChatQrCode{}).
		Where("status = ?", QrCodeStatusUnused).
		Where("expires_at IS NULL OR expires_at > ?", now).
		Count(&stats.UnusedCount).Error; err != nil {
		return nil, err
	}

	return stats, nil
}

// GetQrCodeOCRConfig 获取前端直连 PaddleOCR 所需配置
func (r *Repository) GetQrCodeOCRConfig(ctx context.Context) (*QrCodeOCRConfig, error) {
	config := &QrCodeOCRConfig{
		JobURL: defaultQrCodeOCRJobURL,
		Model:  defaultQrCodeOCRModel,
	}
	var rows []model.SystemConfig
	keys := []string{qrCodeOCRTokenConfigKey, qrCodeOCRJobURLConfigKey, qrCodeOCRModelConfigKey}
	if err := r.db.WithContext(ctx).Where("`key` IN ?", keys).Find(&rows).Error; err != nil {
		return nil, err
	}
	for _, row := range rows {
		switch row.Key {
		case qrCodeOCRTokenConfigKey:
			config.Token = row.Value
		case qrCodeOCRJobURLConfigKey:
			if row.Value != "" {
				config.JobURL = row.Value
			}
		case qrCodeOCRModelConfigKey:
			if row.Value != "" {
				config.Model = row.Value
			}
		}
	}
	return config, nil
}

// UpdateQrCode 更新二维码
func (r *Repository) UpdateQrCode(ctx context.Context, id uint64, req UpdateQrCodeRequest) error {
	var qrcode model.ChatQrCode
	if err := r.db.WithContext(ctx).First(&qrcode, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return ErrQrCodeNotFound
		}
		return err
	}

	updates := make(map[string]interface{})

	if req.ImageURL != nil {
		updates["image_url"] = *req.ImageURL
	}
	if req.GroupName != nil {
		updates["group_name"] = *req.GroupName
	}
	if req.Note != nil {
		updates["note"] = *req.Note
	}
	if req.WecomRenamed != nil {
		updates["wecom_renamed"] = *req.WecomRenamed
	}
	if req.Status != nil {
		// 校验状态值
		if *req.Status != QrCodeStatusUnused && *req.Status != QrCodeStatusUsed && *req.Status != QrCodeStatusDisabled {
			return errors.New("无效的状态值")
		}
		if *req.Status == QrCodeStatusUnused && qrcodeWasIssued(qrcode) {
			return ErrQrCodeCannotReenable
		}
		updates["status"] = *req.Status
	}
	if req.ExpiresAt != nil {
		updates["expires_at"] = req.ExpiresAt
	} else if req.ClearExpiresAt {
		updates["expires_at"] = nil
	}

	if len(updates) == 0 {
		return nil
	}

	if err := r.db.WithContext(ctx).Model(&qrcode).Updates(updates).Error; err != nil {
		return err
	}

	return nil
}

func qrcodeWasIssued(qrcode model.ChatQrCode) bool {
	return qrcode.Status == QrCodeStatusUsed || qrcode.ConversationID != nil || qrcode.UsedAt != nil
}

// DeleteQrCode 删除二维码
func (r *Repository) DeleteQrCode(ctx context.Context, id uint64) error {
	var qrcode model.ChatQrCode
	if err := r.db.WithContext(ctx).First(&qrcode, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return ErrQrCodeNotFound
		}
		return err
	}

	return r.db.WithContext(ctx).Delete(&qrcode).Error
}

// BatchDeleteQrCodes 批量删除二维码
func (r *Repository) BatchDeleteQrCodes(ctx context.Context, ids []uint64) (int64, error) {
	if len(ids) == 0 {
		return 0, nil
	}

	result := r.db.WithContext(ctx).Where("id IN ?", ids).Delete(&model.ChatQrCode{})
	if result.Error != nil {
		return 0, result.Error
	}
	return result.RowsAffected, nil
}

// fetchUnusedQrCode 获取一个未使用且未过期的二维码(带行锁)
func (r *Repository) 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
}

// markQrCodeAsUsed 标记二维码为已使用
func (r *Repository) 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 deliverPendingQrCodes(tx *gorm.DB) ([]model.ChatMessage, error) {
	deliveredMessages := make([]model.ChatMessage, 0)
	for {
		var task model.ChatQrCodeDeliveryTask
		if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
			Where("status = ?", "pending").
			Order("created_at ASC, id ASC").
			First(&task).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return deliveredMessages, nil
			}
			return nil, err
		}

		qrcode, err := fetchUnusedQrCode(tx)
		if err != nil {
			return nil, err
		}
		if qrcode == nil {
			return deliveredMessages, nil
		}

		if err := markQrCodeAsUsed(tx, qrcode.ID, task.ConversationID); err != nil {
			return nil, err
		}
		message, err := sendQrCodeImage(tx, task.ConversationID, qrcode.ImageURL)
		if err != nil {
			now := time.Now()
			if updateErr := tx.Model(&task).Updates(map[string]interface{}{
				"status":        "failed",
				"qrcode_id":     qrcode.ID,
				"error_message": err.Error(),
				"updated_at":    now,
			}).Error; updateErr != nil {
				return nil, updateErr
			}
			continue
		}
		deliveredMessages = append(deliveredMessages, *message)

		now := time.Now()
		if err := tx.Model(&task).Updates(map[string]interface{}{
			"status":        "sent",
			"qrcode_id":     qrcode.ID,
			"error_message": "",
			"sent_at":       now,
			"updated_at":    now,
		}).Error; err != nil {
			return nil, err
		}
	}
}

func (r *Repository) notifyDeliveredQrCodeMessages(messages []model.ChatMessage) {
	if r.hub == nil {
		return
	}
	for _, msg := range messages {
		event := &chathub.ChatEvent{
			Type:           "new_message",
			ConversationID: msg.ConversationID,
			Message: &chathub.MessageData{
				ID:             msg.ID,
				ConversationID: msg.ConversationID,
				SenderType:     msg.SenderType,
				SenderID:       msg.SenderID,
				SenderRole:     msg.SenderRole,
				SenderName:     "系统",
				ContentType:    msg.ContentType,
				Content:        msg.Content,
				AttachmentURLS: decodeStringList(msg.AttachmentURLS),
				CreatedAt:      msg.CreatedAt.Format(time.RFC3339),
			},
		}
		r.hub.NotifyConversation(msg.ConversationID, event)
		r.hub.NotifyAllAdmins(event)
	}
}
